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;
223 * This checks if we have unrelated object classes in our entry's "objectClass"
224 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
225 * or two or more disjunct structural ones.
226 * If one of these conditions are true, blame.
228 static int check_unrelated_objectclasses(struct ldb_module *module,
229 const struct dsdb_schema *schema,
230 const struct dsdb_class *struct_objectclass,
231 struct ldb_message_element *objectclass_element)
233 struct ldb_context *ldb = ldb_module_get_ctx(module);
237 if (schema == NULL) {
241 for (i = 0; i < objectclass_element->num_values; i++) {
242 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
243 &objectclass_element->values[i]);
244 const struct dsdb_class *tmp_class2 = struct_objectclass;
246 /* Pointer comparison can be used due to the same schema str. */
247 if (tmp_class == NULL ||
248 tmp_class == struct_objectclass ||
249 tmp_class->objectClassCategory > 2 ||
250 ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
256 ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
257 tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
258 tmp_class2->subClassOf);
259 if (tmp_class2 == tmp_class) {
267 ldb_asprintf_errstring(ldb,
268 "objectclass: the objectclass '%s' seems to be unrelated to the entry!",
269 tmp_class->lDAPDisplayName);
270 return LDB_ERR_OBJECT_CLASS_VIOLATION;
276 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
278 struct ldb_context *ldb;
279 struct oc_context *ac;
282 ac = talloc_get_type(req->context, struct oc_context);
283 ldb = ldb_module_get_ctx(ac->module);
286 return ldb_module_done(ac->req, NULL, NULL,
287 LDB_ERR_OPERATIONS_ERROR);
289 if (ares->error != LDB_SUCCESS &&
290 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
291 return ldb_module_done(ac->req, ares->controls,
292 ares->response, ares->error);
295 ldb_reset_err_string(ldb);
297 switch (ares->type) {
298 case LDB_REPLY_ENTRY:
299 if (ac->search_res != NULL) {
300 ldb_set_errstring(ldb, "Too many results");
302 return ldb_module_done(ac->req, NULL, NULL,
303 LDB_ERR_OPERATIONS_ERROR);
306 ac->search_res = talloc_steal(ac, ares);
309 case LDB_REPLY_REFERRAL:
316 ret = ac->step_fn(ac);
317 if (ret != LDB_SUCCESS) {
318 return ldb_module_done(ac->req, NULL, NULL, ret);
326 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
328 struct oc_context *ac;
330 ac = talloc_get_type(req->context, struct oc_context);
333 return ldb_module_done(ac->req, NULL, NULL,
334 LDB_ERR_OPERATIONS_ERROR);
337 if (ares->type == LDB_REPLY_REFERRAL) {
338 return ldb_module_send_referral(ac->req, ares->referral);
341 if (ares->error != LDB_SUCCESS) {
342 return ldb_module_done(ac->req, ares->controls,
343 ares->response, ares->error);
346 if (ares->type != LDB_REPLY_DONE) {
348 return ldb_module_done(ac->req, NULL, NULL,
349 LDB_ERR_OPERATIONS_ERROR);
352 return ldb_module_done(ac->req, ares->controls,
353 ares->response, ares->error);
356 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
358 This should mean that if the parent is:
359 CN=Users,DC=samba,DC=example,DC=com
360 and a proposed child is
361 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
363 The resulting DN should be:
365 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
368 static int fix_dn(struct ldb_context *ldb,
370 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
371 struct ldb_dn **fixed_dn)
373 char *upper_rdn_attr;
374 const struct ldb_val *rdn_val;
376 /* Fix up the DN to be in the standard form, taking particular care to
377 * match the parent DN */
378 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
379 if (*fixed_dn == NULL) {
383 /* We need the attribute name in upper case */
384 upper_rdn_attr = strupper_talloc(*fixed_dn,
385 ldb_dn_get_rdn_name(newdn));
386 if (upper_rdn_attr == NULL) {
390 /* Create a new child */
391 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
392 return ldb_operr(ldb);
395 rdn_val = ldb_dn_get_rdn_val(newdn);
396 if (rdn_val == NULL) {
397 return ldb_operr(ldb);
401 /* the rules for rDN length constraints are more complex than
402 this. Until we understand them we need to leave this
403 constraint out. Otherwise we break replication, as windows
404 does sometimes send us rDNs longer than 64 */
405 if (!rdn_val || rdn_val->length > 64) {
406 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
411 /* And replace it with CN=foo (we need the attribute in upper case) */
412 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
416 static int objectclass_do_add(struct oc_context *ac);
418 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
420 struct ldb_context *ldb;
421 struct ldb_request *search_req;
422 struct oc_context *ac;
423 struct ldb_dn *parent_dn;
424 const struct ldb_val *val;
426 static const char * const parent_attrs[] = { "objectClass", NULL };
428 ldb = ldb_module_get_ctx(module);
430 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
432 /* do not manipulate our control entries */
433 if (ldb_dn_is_special(req->op.add.message->dn)) {
434 return ldb_next_request(module, req);
437 /* An add operation on the basedn without "NC-add" operation isn't
439 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
440 unsigned int instanceType;
442 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
444 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
446 /* When we are trying to readd the root basedn then
447 * this is denied, but with an interesting mechanism:
448 * there is generated a referral with the last
449 * component value as hostname. */
450 val = ldb_dn_get_component_val(req->op.add.message->dn,
451 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
453 return ldb_operr(ldb);
455 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
456 ldb_dn_get_linearized(req->op.add.message->dn));
457 if (referral_uri == NULL) {
458 return ldb_module_oom(module);
461 return ldb_module_send_referral(req, referral_uri);
465 ac = oc_init_context(module, req);
467 return ldb_operr(ldb);
470 /* If there isn't a parent, just go on to the add processing */
471 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
472 return objectclass_do_add(ac);
475 /* get copy of parent DN */
476 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
477 if (parent_dn == NULL) {
478 return ldb_operr(ldb);
481 ret = ldb_build_search_req(&search_req, ldb,
482 ac, parent_dn, LDB_SCOPE_BASE,
483 "(objectClass=*)", parent_attrs,
485 ac, get_search_callback,
487 LDB_REQ_SET_LOCATION(search_req);
488 if (ret != LDB_SUCCESS) {
492 ac->step_fn = objectclass_do_add;
494 return ldb_next_request(ac->module, search_req);
499 check if this is a special RODC nTDSDSA add
501 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
502 const struct dsdb_class *objectclass)
504 struct ldb_control *rodc_control;
506 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
509 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
514 rodc_control->critical = false;
518 static int objectclass_do_add(struct oc_context *ac)
520 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
521 struct ldb_request *add_req;
522 struct ldb_message_element *objectclass_element, *el;
523 struct ldb_message *msg;
525 struct class_list *sorted, *current;
526 const char *rdn_name = NULL;
528 const struct dsdb_class *objectclass;
529 struct ldb_dn *objectcategory;
530 int32_t systemFlags = 0;
535 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
537 return ldb_module_oom(ac->module);
540 /* Check if we have a valid parent - this check is needed since
541 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
542 if (ac->search_res == NULL) {
543 unsigned int instanceType;
545 /* An add operation on partition DNs without "NC-add" operation
547 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
549 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
550 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
551 ldb_dn_get_linearized(msg->dn));
552 return LDB_ERR_NO_SUCH_OBJECT;
555 /* Don't keep any error messages - we've to add a partition */
556 ldb_set_errstring(ldb, NULL);
558 /* Fix up the DN to be in the standard form, taking
559 * particular care to match the parent DN */
560 ret = fix_dn(ldb, msg,
561 ac->req->op.add.message->dn,
562 ac->search_res->message->dn,
564 if (ret != LDB_SUCCESS) {
565 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
566 ldb_dn_get_linearized(ac->req->op.add.message->dn));
571 if (ac->schema != NULL) {
572 objectclass_element = ldb_msg_find_element(msg, "objectClass");
573 if (!objectclass_element) {
574 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
575 ldb_dn_get_linearized(msg->dn));
576 return LDB_ERR_OBJECT_CLASS_VIOLATION;
578 if (objectclass_element->num_values == 0) {
579 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
580 ldb_dn_get_linearized(msg->dn));
581 return LDB_ERR_CONSTRAINT_VIOLATION;
584 mem_ctx = talloc_new(ac);
585 if (mem_ctx == NULL) {
586 return ldb_module_oom(ac->module);
589 /* Here we do now get the "objectClass" list from the
591 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
592 objectclass_element, &sorted);
593 if (ret != LDB_SUCCESS) {
594 talloc_free(mem_ctx);
598 ldb_msg_remove_element(msg, objectclass_element);
600 /* Well, now we shouldn't find any additional "objectClass"
601 * message element (required by the AD specification). */
602 objectclass_element = ldb_msg_find_element(msg, "objectClass");
603 if (objectclass_element != NULL) {
604 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
605 ldb_dn_get_linearized(msg->dn));
606 talloc_free(mem_ctx);
607 return LDB_ERR_OBJECT_CLASS_VIOLATION;
610 /* We must completely replace the existing objectClass entry,
611 * because we need it sorted. */
612 ret = ldb_msg_add_empty(msg, "objectClass", 0,
613 &objectclass_element);
614 if (ret != LDB_SUCCESS) {
615 talloc_free(mem_ctx);
619 /* Move from the linked list back into an ldb msg */
620 for (current = sorted; current; current = current->next) {
621 const char *objectclass_name = current->objectclass->lDAPDisplayName;
623 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
624 if (ret != LDB_SUCCESS) {
625 ldb_set_errstring(ldb,
626 "objectclass: could not re-add sorted "
627 "objectclass to modify msg");
628 talloc_free(mem_ctx);
633 talloc_free(mem_ctx);
635 /* Make sure its valid to add an object of this type */
636 objectclass = get_last_structural_class(ac->schema,
637 objectclass_element, ac->req);
638 if(objectclass == NULL) {
639 ldb_asprintf_errstring(ldb,
640 "Failed to find a structural class for %s",
641 ldb_dn_get_linearized(msg->dn));
642 return LDB_ERR_UNWILLING_TO_PERFORM;
645 ret = check_unrelated_objectclasses(ac->module, ac->schema,
647 objectclass_element);
648 if (ret != LDB_SUCCESS) {
652 rdn_name = ldb_dn_get_rdn_name(msg->dn);
653 if (rdn_name == NULL) {
654 return ldb_operr(ldb);
657 for (i = 0; (!found) && (i < objectclass_element->num_values);
659 const struct dsdb_class *tmp_class =
660 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
661 &objectclass_element->values[i]);
663 if (tmp_class == NULL) continue;
665 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
669 ldb_asprintf_errstring(ldb,
670 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
671 rdn_name, objectclass->lDAPDisplayName);
672 return LDB_ERR_NAMING_VIOLATION;
675 if (objectclass->systemOnly &&
676 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
677 !check_rodc_ntdsdsa_add(ac, objectclass)) {
678 ldb_asprintf_errstring(ldb,
679 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
680 objectclass->lDAPDisplayName,
681 ldb_dn_get_linearized(msg->dn));
682 return LDB_ERR_UNWILLING_TO_PERFORM;
685 if (ac->search_res && ac->search_res->message) {
686 struct ldb_message_element *oc_el
687 = ldb_msg_find_element(ac->search_res->message, "objectClass");
689 bool allowed_class = false;
690 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
691 const struct dsdb_class *sclass;
693 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
696 /* We don't know this class? what is going on? */
699 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
700 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
701 allowed_class = true;
707 if (!allowed_class) {
708 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
709 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
710 return LDB_ERR_NAMING_VIOLATION;
714 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
716 if (objectcategory == NULL) {
717 struct dsdb_extended_dn_store_format *dn_format =
718 talloc_get_type(ldb_module_get_private(ac->module),
719 struct dsdb_extended_dn_store_format);
720 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
721 /* Strip off extended components */
722 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
723 objectclass->defaultObjectCategory);
724 value = ldb_dn_alloc_linearized(msg, dn);
727 value = talloc_strdup(msg,
728 objectclass->defaultObjectCategory);
731 return ldb_module_oom(ac->module);
734 ret = ldb_msg_add_string(msg, "objectCategory", value);
735 if (ret != LDB_SUCCESS) {
739 const struct dsdb_class *ocClass =
740 dsdb_class_by_cn_ldb_val(ac->schema,
741 ldb_dn_get_rdn_val(objectcategory));
742 if (ocClass != NULL) {
743 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
744 ocClass->defaultObjectCategory);
745 if (ldb_dn_compare(objectcategory, dn) != 0) {
749 talloc_free(objectcategory);
750 if (ocClass == NULL) {
751 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
752 ldb_dn_get_linearized(msg->dn));
753 return LDB_ERR_OBJECT_CLASS_VIOLATION;
757 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
758 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
762 /* There are very special rules for systemFlags, see MS-ADTS
763 * MS-ADTS 3.1.1.5.2.4 */
765 el = ldb_msg_find_element(msg, "systemFlags");
766 if ((el != NULL) && (el->num_values > 1)) {
767 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
768 ldb_dn_get_linearized(msg->dn));
769 return LDB_ERR_CONSTRAINT_VIOLATION;
772 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
774 ldb_msg_remove_attr(msg, "systemFlags");
776 /* Only the following flags may be set by a client */
777 if (ldb_request_get_control(ac->req,
778 LDB_CONTROL_RELAX_OID) == NULL) {
779 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
780 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
781 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
782 | SYSTEM_FLAG_ATTR_IS_RDN );
785 /* But the last one ("ATTR_IS_RDN") is only allowed on
786 * "attributeSchema" objects. So truncate if it does not fit. */
787 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
788 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
791 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
792 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
793 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
794 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
795 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
796 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
797 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
798 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
799 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
800 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
801 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
802 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
803 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
805 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
807 if (el || systemFlags != 0) {
808 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
810 if (ret != LDB_SUCCESS) {
815 /* make sure that "isCriticalSystemObject" is not specified! */
816 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
818 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
819 ldb_set_errstring(ldb,
820 "objectclass: 'isCriticalSystemObject' must not be specified!");
821 return LDB_ERR_UNWILLING_TO_PERFORM;
825 ret = ldb_build_add_req(&add_req, ldb, ac,
830 LDB_REQ_SET_LOCATION(add_req);
831 if (ret != LDB_SUCCESS) {
835 /* perform the add */
836 return ldb_next_request(ac->module, add_req);
839 static int oc_modify_callback(struct ldb_request *req,
840 struct ldb_reply *ares);
841 static int objectclass_do_mod(struct oc_context *ac);
843 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
845 struct ldb_context *ldb = ldb_module_get_ctx(module);
846 struct ldb_message_element *objectclass_element;
847 struct ldb_message *msg;
848 struct ldb_request *down_req;
849 struct oc_context *ac;
850 bool oc_changes = false;
853 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
855 /* do not manipulate our control entries */
856 if (ldb_dn_is_special(req->op.mod.message->dn)) {
857 return ldb_next_request(module, req);
860 /* As with the "real" AD we don't accept empty messages */
861 if (req->op.mod.message->num_elements == 0) {
862 ldb_set_errstring(ldb, "objectclass: modify message must have "
863 "elements/attributes!");
864 return LDB_ERR_UNWILLING_TO_PERFORM;
867 ac = oc_init_context(module, req);
869 return ldb_operr(ldb);
872 /* Without schema, there isn't much to do here */
873 if (ac->schema == NULL) {
875 return ldb_next_request(module, req);
878 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
880 return ldb_module_oom(ac->module);
883 /* For now change everything except the objectclasses */
885 objectclass_element = ldb_msg_find_element(msg, "objectClass");
886 if (objectclass_element != NULL) {
887 ldb_msg_remove_attr(msg, "objectClass");
891 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
892 * only on application NCs - not on the default ones */
894 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
895 struct ldb_dn *nc_root;
897 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
899 if (ret != LDB_SUCCESS) {
903 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
904 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
905 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
906 ldb_set_errstring(ldb,
907 "objectclass: object class changes on objects under the standard name contexts not allowed!");
908 return LDB_ERR_UNWILLING_TO_PERFORM;
911 talloc_free(nc_root);
914 ret = ldb_build_mod_req(&down_req, ldb, ac,
917 oc_changes ? oc_modify_callback : oc_op_callback,
919 LDB_REQ_SET_LOCATION(down_req);
920 if (ret != LDB_SUCCESS) {
924 return ldb_next_request(module, down_req);
927 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
929 static const char * const attrs[] = { "objectClass", NULL };
930 struct ldb_context *ldb;
931 struct ldb_request *search_req;
932 struct oc_context *ac;
935 ac = talloc_get_type(req->context, struct oc_context);
936 ldb = ldb_module_get_ctx(ac->module);
939 return ldb_module_done(ac->req, NULL, NULL,
940 LDB_ERR_OPERATIONS_ERROR);
943 if (ares->type == LDB_REPLY_REFERRAL) {
944 return ldb_module_send_referral(ac->req, ares->referral);
947 if (ares->error != LDB_SUCCESS) {
948 return ldb_module_done(ac->req, ares->controls,
949 ares->response, ares->error);
952 if (ares->type != LDB_REPLY_DONE) {
954 return ldb_module_done(ac->req, NULL, NULL,
955 LDB_ERR_OPERATIONS_ERROR);
960 /* this looks up the real existing object for fetching some important
961 * information (objectclasses) */
962 ret = ldb_build_search_req(&search_req, ldb,
963 ac, ac->req->op.mod.message->dn,
967 ac, get_search_callback,
969 LDB_REQ_SET_LOCATION(search_req);
970 if (ret != LDB_SUCCESS) {
971 return ldb_module_done(ac->req, NULL, NULL, ret);
974 ac->step_fn = objectclass_do_mod;
976 ret = ldb_next_request(ac->module, search_req);
977 if (ret != LDB_SUCCESS) {
978 return ldb_module_done(ac->req, NULL, NULL, ret);
984 static int objectclass_do_mod(struct oc_context *ac)
986 struct ldb_context *ldb;
987 struct ldb_request *mod_req;
988 struct ldb_message_element *oc_el_entry, *oc_el_change;
989 struct ldb_val *vals;
990 struct ldb_message *msg;
992 struct class_list *sorted, *current;
993 const struct dsdb_class *objectclass;
994 unsigned int i, j, k;
998 ldb = ldb_module_get_ctx(ac->module);
1000 /* we should always have a valid entry when we enter here */
1001 if (ac->search_res == NULL) {
1002 return ldb_operr(ldb);
1005 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1007 if (oc_el_entry == NULL) {
1008 /* existing entry without a valid object class? */
1009 return ldb_operr(ldb);
1012 /* use a new message structure */
1013 msg = ldb_msg_new(ac);
1015 return ldb_module_oom(ac->module);
1018 msg->dn = ac->req->op.mod.message->dn;
1020 mem_ctx = talloc_new(ac);
1021 if (mem_ctx == NULL) {
1022 return ldb_module_oom(ac->module);
1025 /* We've to walk over all "objectClass" message elements */
1026 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
1027 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
1028 "objectClass") != 0) {
1032 oc_el_change = &ac->req->op.mod.message->elements[k];
1034 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
1035 case LDB_FLAG_MOD_ADD:
1036 /* Merge the two message elements */
1037 for (i = 0; i < oc_el_change->num_values; i++) {
1038 for (j = 0; j < oc_el_entry->num_values; j++) {
1039 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1040 (char *)oc_el_entry->values[j].data) == 0) {
1041 ldb_asprintf_errstring(ldb,
1042 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1043 (int)oc_el_change->values[i].length,
1044 (const char *)oc_el_change->values[i].data);
1045 talloc_free(mem_ctx);
1046 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1049 /* append the new object class value - code was
1050 * copied from "ldb_msg_add_value" */
1051 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1053 oc_el_entry->num_values + 1);
1055 talloc_free(mem_ctx);
1056 return ldb_module_oom(ac->module);
1058 oc_el_entry->values = vals;
1059 oc_el_entry->values[oc_el_entry->num_values] =
1060 oc_el_change->values[i];
1061 ++(oc_el_entry->num_values);
1066 case LDB_FLAG_MOD_REPLACE:
1068 * In this case the new "oc_el_entry" is simply
1071 oc_el_entry = oc_el_change;
1075 case LDB_FLAG_MOD_DELETE:
1076 /* Merge the two message elements */
1077 for (i = 0; i < oc_el_change->num_values; i++) {
1079 for (j = 0; j < oc_el_entry->num_values; j++) {
1080 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1081 (char *)oc_el_entry->values[j].data) == 0) {
1083 /* delete the object class value
1084 * - code was copied from
1085 * "ldb_msg_remove_element" */
1086 if (j != oc_el_entry->num_values - 1) {
1087 memmove(&oc_el_entry->values[j],
1088 &oc_el_entry->values[j+1],
1089 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1091 --(oc_el_entry->num_values);
1096 /* we cannot delete a not existing
1098 ldb_asprintf_errstring(ldb,
1099 "objectclass: cannot delete this objectclass: '%.*s'!",
1100 (int)oc_el_change->values[i].length,
1101 (const char *)oc_el_change->values[i].data);
1102 talloc_free(mem_ctx);
1103 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1110 /* Get the new top-most structural object class */
1111 objectclass = get_last_structural_class(ac->schema, oc_el_entry,
1113 if (objectclass == NULL) {
1114 ldb_set_errstring(ldb,
1115 "objectclass: cannot delete all structural objectclasses!");
1116 talloc_free(mem_ctx);
1117 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1120 ret = check_unrelated_objectclasses(ac->module, ac->schema,
1123 if (ret != LDB_SUCCESS) {
1124 talloc_free(mem_ctx);
1128 /* Now do the sorting */
1129 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1130 oc_el_entry, &sorted);
1131 if (ret != LDB_SUCCESS) {
1132 talloc_free(mem_ctx);
1136 /* (Re)-add an empty "objectClass" attribute on the object
1137 * classes change message "msg". */
1138 ldb_msg_remove_attr(msg, "objectClass");
1139 ret = ldb_msg_add_empty(msg, "objectClass",
1140 LDB_FLAG_MOD_REPLACE, &oc_el_entry);
1141 if (ret != LDB_SUCCESS) {
1142 talloc_free(mem_ctx);
1146 /* Move from the linked list back into an ldb msg */
1147 for (current = sorted; current; current = current->next) {
1148 const char *objectclass_name = current->objectclass->lDAPDisplayName;
1150 ret = ldb_msg_add_string(msg, "objectClass",
1152 if (ret != LDB_SUCCESS) {
1153 ldb_set_errstring(ldb,
1154 "objectclass: could not re-add sorted objectclasses!");
1155 talloc_free(mem_ctx);
1161 talloc_free(mem_ctx);
1163 /* Now we have the real and definitive change left to do */
1165 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1170 LDB_REQ_SET_LOCATION(mod_req);
1171 if (ret != LDB_SUCCESS) {
1175 return ldb_next_request(ac->module, mod_req);
1178 static int objectclass_do_rename(struct oc_context *ac);
1180 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1182 static const char * const attrs[] = { "objectClass", NULL };
1183 struct ldb_context *ldb;
1184 struct ldb_request *search_req;
1185 struct oc_context *ac;
1186 struct ldb_dn *parent_dn;
1189 ldb = ldb_module_get_ctx(module);
1191 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1193 /* do not manipulate our control entries */
1194 if (ldb_dn_is_special(req->op.rename.olddn)) {
1195 return ldb_next_request(module, req);
1198 ac = oc_init_context(module, req);
1200 return ldb_operr(ldb);
1203 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1204 if (parent_dn == NULL) {
1205 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1206 ldb_dn_get_linearized(req->op.rename.olddn));
1207 return LDB_ERR_NO_SUCH_OBJECT;
1210 /* this looks up the parent object for fetching some important
1211 * information (objectclasses, DN normalisation...) */
1212 ret = ldb_build_search_req(&search_req, ldb,
1213 ac, parent_dn, LDB_SCOPE_BASE,
1216 ac, get_search_callback,
1218 LDB_REQ_SET_LOCATION(search_req);
1219 if (ret != LDB_SUCCESS) {
1223 /* we have to add the show recycled control, as otherwise DRS
1224 deletes will be refused as we will think the target parent
1226 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1229 if (ret != LDB_SUCCESS) {
1233 ac->step_fn = objectclass_do_rename;
1235 return ldb_next_request(ac->module, search_req);
1238 static int objectclass_do_rename2(struct oc_context *ac);
1240 static int objectclass_do_rename(struct oc_context *ac)
1242 static const char * const attrs[] = { "objectClass", NULL };
1243 struct ldb_context *ldb;
1244 struct ldb_request *search_req;
1247 ldb = ldb_module_get_ctx(ac->module);
1249 /* Check if we have a valid parent - this check is needed since
1250 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1251 if (ac->search_res == NULL) {
1252 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1253 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1254 return LDB_ERR_OTHER;
1257 /* now assign "search_res2" to the parent entry to have "search_res"
1258 * free for another lookup */
1259 ac->search_res2 = ac->search_res;
1260 ac->search_res = NULL;
1262 /* this looks up the real existing object for fetching some important
1263 * information (objectclasses) */
1264 ret = ldb_build_search_req(&search_req, ldb,
1265 ac, ac->req->op.rename.olddn,
1269 ac, get_search_callback,
1271 LDB_REQ_SET_LOCATION(search_req);
1272 if (ret != LDB_SUCCESS) {
1276 ac->step_fn = objectclass_do_rename2;
1278 return ldb_next_request(ac->module, search_req);
1281 static int objectclass_do_rename2(struct oc_context *ac)
1283 struct ldb_context *ldb;
1284 struct ldb_request *rename_req;
1285 struct ldb_dn *fixed_dn;
1288 ldb = ldb_module_get_ctx(ac->module);
1290 /* Check if we have a valid entry - this check is needed since
1291 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1292 if (ac->search_res == NULL) {
1293 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1294 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1295 return LDB_ERR_NO_SUCH_OBJECT;
1298 if (ac->schema != NULL) {
1299 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1300 const struct dsdb_class *objectclass;
1301 const char *rdn_name;
1302 bool allowed_class = false;
1306 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1308 if (oc_el_entry == NULL) {
1309 /* existing entry without a valid object class? */
1310 return ldb_operr(ldb);
1312 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1313 if (objectclass == NULL) {
1314 /* existing entry without a valid object class? */
1315 return ldb_operr(ldb);
1318 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1319 if (rdn_name == NULL) {
1320 return ldb_operr(ldb);
1323 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1324 const struct dsdb_class *tmp_class =
1325 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1326 &oc_el_entry->values[i]);
1328 if (tmp_class == NULL) continue;
1330 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1334 ldb_asprintf_errstring(ldb,
1335 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1336 rdn_name, objectclass->lDAPDisplayName);
1337 return LDB_ERR_UNWILLING_TO_PERFORM;
1340 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1342 if (oc_el_parent == NULL) {
1343 /* existing entry without a valid object class? */
1344 return ldb_operr(ldb);
1347 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1348 const struct dsdb_class *sclass;
1350 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1351 &oc_el_parent->values[i]);
1353 /* We don't know this class? what is going on? */
1356 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1357 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1358 allowed_class = true;
1364 if (!allowed_class) {
1365 ldb_asprintf_errstring(ldb,
1366 "objectclass: structural objectClass %s is not a valid child class for %s",
1367 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1368 return LDB_ERR_NAMING_VIOLATION;
1372 /* Ensure we are not trying to rename it to be a child of itself */
1373 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1374 ac->req->op.rename.newdn) == 0) &&
1375 (ldb_dn_compare(ac->req->op.rename.olddn,
1376 ac->req->op.rename.newdn) != 0)) {
1377 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1378 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1379 return LDB_ERR_UNWILLING_TO_PERFORM;
1382 /* Fix up the DN to be in the standard form, taking
1383 * particular care to match the parent DN */
1384 ret = fix_dn(ldb, ac,
1385 ac->req->op.rename.newdn,
1386 ac->search_res2->message->dn,
1388 if (ret != LDB_SUCCESS) {
1389 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1390 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1395 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1396 ac->req->op.rename.olddn, fixed_dn,
1400 LDB_REQ_SET_LOCATION(rename_req);
1401 if (ret != LDB_SUCCESS) {
1405 /* perform the rename */
1406 return ldb_next_request(ac->module, rename_req);
1409 static int objectclass_do_delete(struct oc_context *ac);
1411 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1413 static const char * const attrs[] = { "nCName", "objectClass",
1416 "isCriticalSystemObject", NULL };
1417 struct ldb_context *ldb;
1418 struct ldb_request *search_req;
1419 struct oc_context *ac;
1422 ldb = ldb_module_get_ctx(module);
1424 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1426 /* do not manipulate our control entries */
1427 if (ldb_dn_is_special(req->op.del.dn)) {
1428 return ldb_next_request(module, req);
1431 /* Bypass the constraint checks when we do have the "RELAX" control
1433 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1434 return ldb_next_request(module, req);
1437 ac = oc_init_context(module, req);
1439 return ldb_operr(ldb);
1442 /* this looks up the entry object for fetching some important
1443 * information (object classes, system flags...) */
1444 ret = ldb_build_search_req(&search_req, ldb,
1445 ac, req->op.del.dn, LDB_SCOPE_BASE,
1447 attrs, req->controls,
1448 ac, get_search_callback,
1450 LDB_REQ_SET_LOCATION(search_req);
1451 if (ret != LDB_SUCCESS) {
1455 ac->step_fn = objectclass_do_delete;
1457 return ldb_next_request(ac->module, search_req);
1460 static int objectclass_do_delete(struct oc_context *ac)
1462 struct ldb_context *ldb;
1464 int32_t systemFlags;
1465 bool isCriticalSystemObject;
1468 ldb = ldb_module_get_ctx(ac->module);
1470 /* Check if we have a valid entry - this check is needed since
1471 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1472 if (ac->search_res == NULL) {
1473 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1474 ldb_dn_get_linearized(ac->req->op.del.dn));
1475 return LDB_ERR_NO_SUCH_OBJECT;
1478 /* DC's ntDSDSA object */
1479 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1480 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1481 ldb_dn_get_linearized(ac->req->op.del.dn));
1482 return LDB_ERR_UNWILLING_TO_PERFORM;
1485 /* DC's rIDSet object */
1486 /* Perform this check only when it does exist - this is needed in order
1487 * to don't let existing provisions break. */
1488 ret = samdb_rid_set_dn(ldb, ac, &dn);
1489 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1492 if (ret == LDB_SUCCESS) {
1493 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1495 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1496 ldb_dn_get_linearized(ac->req->op.del.dn));
1497 return LDB_ERR_UNWILLING_TO_PERFORM;
1502 /* Only trusted request from system account are allowed to delete
1505 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1506 (ldb_req_is_untrusted(ac->req) ||
1507 !dsdb_module_am_system(ac->module))) {
1508 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1509 ldb_dn_get_linearized(ac->req->op.del.dn));
1510 return LDB_ERR_UNWILLING_TO_PERFORM;
1513 /* crossRef objects regarding config, schema and default domain NCs */
1514 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1515 "crossRef") != NULL) {
1516 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1518 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1519 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1522 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1523 ldb_dn_get_linearized(ac->req->op.del.dn));
1524 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1526 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1529 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1530 ldb_dn_get_linearized(ac->req->op.del.dn));
1531 return LDB_ERR_UNWILLING_TO_PERFORM;
1538 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1540 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1541 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1542 ldb_dn_get_linearized(ac->req->op.del.dn));
1543 return LDB_ERR_UNWILLING_TO_PERFORM;
1546 /* isCriticalSystemObject - but this only applies on tree delete
1547 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1548 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1549 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1550 "isCriticalSystemObject", false);
1551 if (isCriticalSystemObject) {
1553 * Following the explaination from Microsoft
1554 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1555 * "I finished the investigation on this behavior.
1556 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1557 * every object in the tree will be checked to see if it has isCriticalSystemObject
1558 * set to TRUE, including the root node on which the delete operation is performed
1559 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1560 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1561 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1562 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1565 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1566 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1567 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1568 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1569 ldb_asprintf_errstring(ldb,
1570 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1571 ldb_dn_get_linearized(ac->req->op.del.dn));
1572 return LDB_ERR_UNWILLING_TO_PERFORM;
1577 return ldb_next_request(ac->module, ac->req);
1580 static int objectclass_init(struct ldb_module *module)
1582 struct ldb_context *ldb = ldb_module_get_ctx(module);
1585 /* Init everything else */
1586 ret = ldb_next_init(module);
1587 if (ret != LDB_SUCCESS) {
1591 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1592 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1594 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1595 if (ret != LDB_SUCCESS) {
1596 ldb_debug(ldb, LDB_DEBUG_ERROR,
1597 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1598 return ldb_operr(ldb);
1604 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1605 .name = "objectclass",
1606 .add = objectclass_add,
1607 .modify = objectclass_modify,
1608 .rename = objectclass_rename,
1609 .del = objectclass_delete,
1610 .init_context = objectclass_init
1613 int ldb_objectclass_module_init(const char *version)
1615 LDB_MODULE_CHECK_VERSION(version);
1616 return ldb_register_module(&ldb_objectclass_module_ops);