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 return ldb_operr(ldb);
427 ret = ldb_build_search_req(&search_req, ldb,
428 ac, parent_dn, LDB_SCOPE_BASE,
429 "(objectClass=*)", parent_attrs,
431 ac, get_search_callback,
433 LDB_REQ_SET_LOCATION(search_req);
434 if (ret != LDB_SUCCESS) {
438 ac->step_fn = objectclass_do_add;
440 return ldb_next_request(ac->module, search_req);
445 check if this is a special RODC nTDSDSA add
447 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
448 const struct dsdb_class *objectclass)
450 struct ldb_control *rodc_control;
452 if (strcasecmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
455 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
460 rodc_control->critical = false;
464 static int objectclass_do_add(struct oc_context *ac)
466 struct ldb_context *ldb = 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 /* LSA-specific objectclasses per default not
569 * allowed to be created over LDAP, so we need
570 * to tell if this connection is LDAP (ie
571 * marked as untrusted), and if the client is
572 * adding these particular objectClass values
575 /* Hongwei Sun from Microsoft explians:
576 The constraint in 3.1.1.5.2.2 MS-ADTS means that the TDO
577 cannot be added through LDAP interface, instead it can only be
578 created through LSA Policy API. This is also explained in
579 7.1.6.9.7 MS-ADTS as follows:
581 "Despite being replicated normally between peer DCs in a domain,
582 the process of creating or manipulating TDOs is specifically
583 restricted to the LSA Policy APIs, as detailed in [MS-LSAD] section
584 3.1.1.5. Unlike other objects in the DS, TDOs may not be created or
585 manipulated by client machines over the LDAPv3 transport."
588 if (ldb_req_is_untrusted(ac->req) &&
589 ((strcasecmp(objectclass_name, "secret") == 0) ||
590 (strcasecmp(objectclass_name, "trustedDomain") == 0))) {
591 ldb_asprintf_errstring(ldb,
592 "objectclass: object class '%s' is LSA-specific, rejecting creation of '%s' over LDAP!",
594 ldb_dn_get_linearized(msg->dn));
595 talloc_free(mem_ctx);
596 return LDB_ERR_UNWILLING_TO_PERFORM;
599 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
600 if (ret != LDB_SUCCESS) {
601 ldb_set_errstring(ldb,
602 "objectclass: could not re-add sorted "
603 "objectclass to modify msg");
604 talloc_free(mem_ctx);
609 talloc_free(mem_ctx);
611 /* Retrive the message again so get_last_structural_class works */
612 objectclass_element = ldb_msg_find_element(msg, "objectClass");
614 /* Make sure its valid to add an object of this type */
615 objectclass = get_last_structural_class(ac->schema,
616 objectclass_element);
617 if(objectclass == NULL) {
618 ldb_asprintf_errstring(ldb,
619 "Failed to find a structural class for %s",
620 ldb_dn_get_linearized(msg->dn));
621 return LDB_ERR_UNWILLING_TO_PERFORM;
624 rdn_name = ldb_dn_get_rdn_name(msg->dn);
625 if (rdn_name == NULL) {
626 return ldb_operr(ldb);
629 for (i = 0; (!found) && (i < objectclass_element->num_values);
631 const struct dsdb_class *tmp_class =
632 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
633 &objectclass_element->values[i]);
635 if (tmp_class == NULL) continue;
637 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
641 ldb_asprintf_errstring(ldb,
642 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
643 rdn_name, objectclass->lDAPDisplayName);
644 return LDB_ERR_NAMING_VIOLATION;
647 if (objectclass->systemOnly &&
648 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
649 !check_rodc_ntdsdsa_add(ac, objectclass)) {
650 ldb_asprintf_errstring(ldb,
651 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
652 objectclass->lDAPDisplayName,
653 ldb_dn_get_linearized(msg->dn));
654 return LDB_ERR_UNWILLING_TO_PERFORM;
657 if (ac->search_res && ac->search_res->message) {
658 struct ldb_message_element *oc_el
659 = ldb_msg_find_element(ac->search_res->message, "objectClass");
661 bool allowed_class = false;
662 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
663 const struct dsdb_class *sclass;
665 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
668 /* We don't know this class? what is going on? */
671 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
672 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
673 allowed_class = true;
679 if (!allowed_class) {
680 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
681 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
682 return LDB_ERR_NAMING_VIOLATION;
686 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
688 if (objectcategory == NULL) {
689 struct dsdb_extended_dn_store_format *dn_format =
690 talloc_get_type(ldb_module_get_private(ac->module),
691 struct dsdb_extended_dn_store_format);
692 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
693 /* Strip off extended components */
694 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
695 objectclass->defaultObjectCategory);
696 value = ldb_dn_alloc_linearized(msg, dn);
699 value = talloc_strdup(msg,
700 objectclass->defaultObjectCategory);
703 return ldb_module_oom(ac->module);
706 ret = ldb_msg_add_string(msg, "objectCategory", value);
707 if (ret != LDB_SUCCESS) {
711 const struct dsdb_class *ocClass =
712 dsdb_class_by_cn_ldb_val(ac->schema,
713 ldb_dn_get_rdn_val(objectcategory));
714 if (ocClass != NULL) {
715 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
716 ocClass->defaultObjectCategory);
717 if (ldb_dn_compare(objectcategory, dn) != 0) {
721 talloc_free(objectcategory);
722 if (ocClass == NULL) {
723 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
724 ldb_dn_get_linearized(msg->dn));
725 return LDB_ERR_OBJECT_CLASS_VIOLATION;
729 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
730 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
734 /* There are very special rules for systemFlags, see MS-ADTS
735 * MS-ADTS 3.1.1.5.2.4 */
737 el = ldb_msg_find_element(msg, "systemFlags");
738 if ((el != NULL) && (el->num_values > 1)) {
739 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
740 ldb_dn_get_linearized(msg->dn));
741 return LDB_ERR_CONSTRAINT_VIOLATION;
744 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
746 ldb_msg_remove_attr(msg, "systemFlags");
748 /* Only the following flags may be set by a client */
749 if (ldb_request_get_control(ac->req,
750 LDB_CONTROL_RELAX_OID) == NULL) {
751 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
752 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
753 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
754 | SYSTEM_FLAG_ATTR_IS_RDN );
757 /* But the last one ("ATTR_IS_RDN") is only allowed on
758 * "attributeSchema" objects. So truncate if it does not fit. */
759 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
760 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
763 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
764 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
765 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
766 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
767 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
768 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
770 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
771 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
772 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
773 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
776 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
778 if (el || systemFlags != 0) {
779 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
781 if (ret != LDB_SUCCESS) {
786 /* make sure that "isCriticalSystemObject" is not specified! */
787 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
789 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
790 ldb_set_errstring(ldb,
791 "objectclass: 'isCriticalSystemObject' must not be specified!");
792 return LDB_ERR_UNWILLING_TO_PERFORM;
796 ret = ldb_msg_sanity_check(ldb, msg);
797 if (ret != LDB_SUCCESS) {
801 ret = ldb_build_add_req(&add_req, ldb, ac,
806 LDB_REQ_SET_LOCATION(add_req);
807 if (ret != LDB_SUCCESS) {
811 /* perform the add */
812 return ldb_next_request(ac->module, add_req);
815 static int oc_modify_callback(struct ldb_request *req,
816 struct ldb_reply *ares);
817 static int objectclass_do_mod(struct oc_context *ac);
819 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
821 struct ldb_context *ldb = ldb_module_get_ctx(module);
822 struct ldb_message_element *objectclass_element;
823 struct ldb_message *msg;
824 struct ldb_request *down_req;
825 struct oc_context *ac;
826 bool oc_changes = false;
829 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
831 /* do not manipulate our control entries */
832 if (ldb_dn_is_special(req->op.mod.message->dn)) {
833 return ldb_next_request(module, req);
836 /* As with the "real" AD we don't accept empty messages */
837 if (req->op.mod.message->num_elements == 0) {
838 ldb_set_errstring(ldb, "objectclass: modify message must have "
839 "elements/attributes!");
840 return LDB_ERR_UNWILLING_TO_PERFORM;
843 ac = oc_init_context(module, req);
845 return ldb_operr(ldb);
848 /* Without schema, there isn't much to do here */
849 if (ac->schema == NULL) {
851 return ldb_next_request(module, req);
854 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
856 return ldb_module_oom(ac->module);
859 /* For now change everything except the objectclasses */
861 objectclass_element = ldb_msg_find_element(msg, "objectClass");
862 if (objectclass_element != NULL) {
863 ldb_msg_remove_attr(msg, "objectClass");
867 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
868 * only on application NCs - not on the standard DCs */
870 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
871 struct ldb_dn *nc_root;
873 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
875 if (ret != LDB_SUCCESS) {
879 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
880 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
881 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
882 ldb_set_errstring(ldb,
883 "objectclass: object class changes on objects under the standard name contexts not allowed!");
884 return LDB_ERR_UNWILLING_TO_PERFORM;
887 talloc_free(nc_root);
890 ret = ldb_build_mod_req(&down_req, ldb, ac,
893 oc_changes ? oc_modify_callback : oc_op_callback,
895 LDB_REQ_SET_LOCATION(down_req);
896 if (ret != LDB_SUCCESS) {
900 return ldb_next_request(module, down_req);
903 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
905 static const char * const attrs[] = { "objectClass", NULL };
906 struct ldb_context *ldb;
907 struct ldb_request *search_req;
908 struct oc_context *ac;
911 ac = talloc_get_type(req->context, struct oc_context);
912 ldb = ldb_module_get_ctx(ac->module);
915 return ldb_module_done(ac->req, NULL, NULL,
916 LDB_ERR_OPERATIONS_ERROR);
919 if (ares->type == LDB_REPLY_REFERRAL) {
920 return ldb_module_send_referral(ac->req, ares->referral);
923 if (ares->error != LDB_SUCCESS) {
924 return ldb_module_done(ac->req, ares->controls,
925 ares->response, ares->error);
928 if (ares->type != LDB_REPLY_DONE) {
930 return ldb_module_done(ac->req, NULL, NULL,
931 LDB_ERR_OPERATIONS_ERROR);
936 /* this looks up the real existing object for fetching some important
937 * informations (objectclasses) */
938 ret = ldb_build_search_req(&search_req, ldb,
939 ac, ac->req->op.mod.message->dn,
943 ac, get_search_callback,
945 LDB_REQ_SET_LOCATION(search_req);
946 if (ret != LDB_SUCCESS) {
947 return ldb_module_done(ac->req, NULL, NULL, ret);
950 ac->step_fn = objectclass_do_mod;
952 ret = ldb_next_request(ac->module, search_req);
953 if (ret != LDB_SUCCESS) {
954 return ldb_module_done(ac->req, NULL, NULL, ret);
960 static int objectclass_do_mod(struct oc_context *ac)
962 struct ldb_context *ldb;
963 struct ldb_request *mod_req;
965 struct ldb_message_element *oc_el_entry, *oc_el_change;
966 struct ldb_val *vals;
967 struct ldb_message *msg;
969 struct class_list *sorted, *current;
970 const struct dsdb_class *objectclass;
971 unsigned int i, j, k;
972 bool found, replace = false;
975 ldb = ldb_module_get_ctx(ac->module);
977 /* we should always have a valid entry when we enter here */
978 if (ac->search_res == NULL) {
979 return ldb_operr(ldb);
982 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
984 if (oc_el_entry == NULL) {
985 /* existing entry without a valid object class? */
986 return ldb_operr(ldb);
989 /* use a new message structure */
990 msg = ldb_msg_new(ac);
992 return ldb_module_oom(ac->module);
995 msg->dn = ac->req->op.mod.message->dn;
997 mem_ctx = talloc_new(ac);
998 if (mem_ctx == NULL) {
999 return ldb_module_oom(ac->module);
1002 /* We've to walk over all "objectClass" message elements */
1003 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
1004 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
1005 "objectClass") != 0) {
1009 oc_el_change = &ac->req->op.mod.message->elements[k];
1011 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
1012 case LDB_FLAG_MOD_ADD:
1013 /* Merge the two message elements */
1014 for (i = 0; i < oc_el_change->num_values; i++) {
1015 for (j = 0; j < oc_el_entry->num_values; j++) {
1016 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1017 (char *)oc_el_entry->values[j].data) == 0) {
1018 ldb_asprintf_errstring(ldb,
1019 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1020 (int)oc_el_change->values[i].length,
1021 (const char *)oc_el_change->values[i].data);
1022 talloc_free(mem_ctx);
1023 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1026 /* append the new object class value - code was
1027 * copied from "ldb_msg_add_value" */
1028 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1030 oc_el_entry->num_values + 1);
1032 talloc_free(mem_ctx);
1033 return ldb_module_oom(ac->module);
1035 oc_el_entry->values = vals;
1036 oc_el_entry->values[oc_el_entry->num_values] =
1037 oc_el_change->values[i];
1038 ++(oc_el_entry->num_values);
1041 objectclass = get_last_structural_class(ac->schema,
1043 if (objectclass != NULL) {
1044 ldb_asprintf_errstring(ldb,
1045 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1046 objectclass->lDAPDisplayName);
1047 talloc_free(mem_ctx);
1048 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1051 /* Now do the sorting */
1052 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1053 oc_el_entry, &sorted);
1054 if (ret != LDB_SUCCESS) {
1055 talloc_free(mem_ctx);
1061 case LDB_FLAG_MOD_REPLACE:
1062 /* Do the sorting for the change message element */
1063 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1064 oc_el_change, &sorted);
1065 if (ret != LDB_SUCCESS) {
1066 talloc_free(mem_ctx);
1070 /* this is a replace */
1075 case LDB_FLAG_MOD_DELETE:
1076 /* get the actual top-most structural objectclass */
1077 objectclass = get_last_structural_class(ac->schema,
1079 if (objectclass == NULL) {
1080 /* no structural objectclass? */
1081 talloc_free(mem_ctx);
1082 return ldb_operr(ldb);
1085 /* Merge the two message elements */
1086 for (i = 0; i < oc_el_change->num_values; i++) {
1088 for (j = 0; j < oc_el_entry->num_values; j++) {
1089 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1090 (char *)oc_el_entry->values[j].data) == 0) {
1092 /* delete the object class value
1093 * - code was copied from
1094 * "ldb_msg_remove_element" */
1095 if (j != oc_el_entry->num_values - 1) {
1096 memmove(&oc_el_entry->values[j],
1097 &oc_el_entry->values[j+1],
1098 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1100 --(oc_el_entry->num_values);
1105 /* we cannot delete a not existing
1107 ldb_asprintf_errstring(ldb,
1108 "objectclass: cannot delete this objectclass: '%.*s'!",
1109 (int)oc_el_change->values[i].length,
1110 (const char *)oc_el_change->values[i].data);
1111 talloc_free(mem_ctx);
1112 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1116 /* Make sure that the top-most structural object class
1117 * hasn't been deleted */
1119 for (i = 0; i < oc_el_entry->num_values; i++) {
1120 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1121 (char *)oc_el_entry->values[i].data) == 0) {
1127 ldb_asprintf_errstring(ldb,
1128 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1129 objectclass->lDAPDisplayName);
1130 talloc_free(mem_ctx);
1131 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1134 /* Now do the sorting */
1135 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1136 oc_el_entry, &sorted);
1137 if (ret != LDB_SUCCESS) {
1138 talloc_free(mem_ctx);
1145 /* (Re)-add an empty "objectClass" attribute on the object
1146 * classes change message "msg". */
1147 ldb_msg_remove_attr(msg, "objectClass");
1148 ret = ldb_msg_add_empty(msg, "objectClass",
1149 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1150 if (ret != LDB_SUCCESS) {
1151 talloc_free(mem_ctx);
1155 /* Move from the linked list back into an ldb msg */
1156 for (current = sorted; current; current = current->next) {
1157 value = talloc_strdup(msg,
1158 current->objectclass->lDAPDisplayName);
1159 if (value == NULL) {
1160 talloc_free(mem_ctx);
1161 return ldb_module_oom(ac->module);
1163 ret = ldb_msg_add_string(msg, "objectClass", value);
1164 if (ret != LDB_SUCCESS) {
1165 ldb_set_errstring(ldb,
1166 "objectclass: could not re-add sorted objectclasses!");
1167 talloc_free(mem_ctx);
1173 /* Well, on replace we are nearly done: we have to test
1174 * if the change and entry message element are identical
1175 * ly. We can use "ldb_msg_element_compare" since now
1176 * the specified objectclasses match for sure in case.
1178 ret = ldb_msg_element_compare(oc_el_entry,
1181 ret = ldb_msg_element_compare(oc_el_change,
1185 /* they are the same so we are done in this
1187 talloc_free(mem_ctx);
1188 return ldb_module_done(ac->req, NULL, NULL,
1191 ldb_set_errstring(ldb,
1192 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1193 talloc_free(mem_ctx);
1194 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1198 /* Now we've applied all changes from "oc_el_change" to
1199 * "oc_el_entry" therefore the new "oc_el_entry" will be
1200 * "oc_el_change". */
1201 oc_el_entry = oc_el_change;
1204 talloc_free(mem_ctx);
1206 /* Now we have the real and definitive change left to do */
1208 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1213 LDB_REQ_SET_LOCATION(mod_req);
1214 if (ret != LDB_SUCCESS) {
1218 return ldb_next_request(ac->module, mod_req);
1221 static int objectclass_do_rename(struct oc_context *ac);
1223 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1225 static const char * const attrs[] = { "objectClass", NULL };
1226 struct ldb_context *ldb;
1227 struct ldb_request *search_req;
1228 struct oc_context *ac;
1229 struct ldb_dn *parent_dn;
1232 ldb = ldb_module_get_ctx(module);
1234 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1236 /* do not manipulate our control entries */
1237 if (ldb_dn_is_special(req->op.rename.olddn)) {
1238 return ldb_next_request(module, req);
1241 ac = oc_init_context(module, req);
1243 return ldb_operr(ldb);
1246 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1247 if (parent_dn == NULL) {
1248 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1249 ldb_dn_get_linearized(req->op.rename.olddn));
1250 return LDB_ERR_NO_SUCH_OBJECT;
1253 /* this looks up the parent object for fetching some important
1254 * informations (objectclasses, DN normalisation...) */
1255 ret = ldb_build_search_req(&search_req, ldb,
1256 ac, parent_dn, LDB_SCOPE_BASE,
1259 ac, get_search_callback,
1261 LDB_REQ_SET_LOCATION(search_req);
1262 if (ret != LDB_SUCCESS) {
1266 /* we have to add the show recycled control, as otherwise DRS
1267 deletes will be refused as we will think the target parent
1269 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1272 if (ret != LDB_SUCCESS) {
1276 ac->step_fn = objectclass_do_rename;
1278 return ldb_next_request(ac->module, search_req);
1281 static int objectclass_do_rename2(struct oc_context *ac);
1283 static int objectclass_do_rename(struct oc_context *ac)
1285 static const char * const attrs[] = { "objectClass", NULL };
1286 struct ldb_context *ldb;
1287 struct ldb_request *search_req;
1290 ldb = ldb_module_get_ctx(ac->module);
1292 /* Check if we have a valid parent - this check is needed since
1293 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1294 if (ac->search_res == NULL) {
1295 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1296 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1297 return LDB_ERR_OTHER;
1300 /* now assign "search_res2" to the parent entry to have "search_res"
1301 * free for another lookup */
1302 ac->search_res2 = ac->search_res;
1303 ac->search_res = NULL;
1305 /* this looks up the real existing object for fetching some important
1306 * informations (objectclasses) */
1307 ret = ldb_build_search_req(&search_req, ldb,
1308 ac, ac->req->op.rename.olddn,
1312 ac, get_search_callback,
1314 LDB_REQ_SET_LOCATION(search_req);
1315 if (ret != LDB_SUCCESS) {
1319 ac->step_fn = objectclass_do_rename2;
1321 return ldb_next_request(ac->module, search_req);
1324 static int objectclass_do_rename2(struct oc_context *ac)
1326 struct ldb_context *ldb;
1327 struct ldb_request *rename_req;
1328 struct ldb_dn *fixed_dn;
1331 ldb = ldb_module_get_ctx(ac->module);
1333 /* Check if we have a valid entry - this check is needed since
1334 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1335 if (ac->search_res == NULL) {
1336 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1337 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1338 return LDB_ERR_NO_SUCH_OBJECT;
1341 if (ac->schema != NULL) {
1342 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1343 const struct dsdb_class *objectclass;
1344 const char *rdn_name;
1345 bool allowed_class = false;
1349 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1351 if (oc_el_entry == NULL) {
1352 /* existing entry without a valid object class? */
1353 return ldb_operr(ldb);
1355 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1356 if (objectclass == NULL) {
1357 /* existing entry without a valid object class? */
1358 return ldb_operr(ldb);
1361 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1362 if (rdn_name == NULL) {
1363 return ldb_operr(ldb);
1366 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1367 const struct dsdb_class *tmp_class =
1368 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1369 &oc_el_entry->values[i]);
1371 if (tmp_class == NULL) continue;
1373 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1377 ldb_asprintf_errstring(ldb,
1378 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1379 rdn_name, objectclass->lDAPDisplayName);
1380 return LDB_ERR_UNWILLING_TO_PERFORM;
1383 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1385 if (oc_el_parent == NULL) {
1386 /* existing entry without a valid object class? */
1387 return ldb_operr(ldb);
1390 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1391 const struct dsdb_class *sclass;
1393 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1394 &oc_el_parent->values[i]);
1396 /* We don't know this class? what is going on? */
1399 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1400 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1401 allowed_class = true;
1407 if (!allowed_class) {
1408 ldb_asprintf_errstring(ldb,
1409 "objectclass: structural objectClass %s is not a valid child class for %s",
1410 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1411 return LDB_ERR_NAMING_VIOLATION;
1415 /* Ensure we are not trying to rename it to be a child of itself */
1416 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1417 ac->req->op.rename.newdn) == 0) &&
1418 (ldb_dn_compare(ac->req->op.rename.olddn,
1419 ac->req->op.rename.newdn) != 0)) {
1420 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1421 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1422 return LDB_ERR_UNWILLING_TO_PERFORM;
1425 /* Fix up the DN to be in the standard form, taking
1426 * particular care to match the parent DN */
1427 ret = fix_dn(ldb, ac,
1428 ac->req->op.rename.newdn,
1429 ac->search_res2->message->dn,
1431 if (ret != LDB_SUCCESS) {
1432 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1433 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1438 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1439 ac->req->op.rename.olddn, fixed_dn,
1443 LDB_REQ_SET_LOCATION(rename_req);
1444 if (ret != LDB_SUCCESS) {
1448 /* perform the rename */
1449 return ldb_next_request(ac->module, rename_req);
1452 static int objectclass_do_delete(struct oc_context *ac);
1454 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1456 static const char * const attrs[] = { "nCName", "objectClass",
1458 "isCriticalSystemObject", NULL };
1459 struct ldb_context *ldb;
1460 struct ldb_request *search_req;
1461 struct oc_context *ac;
1464 ldb = ldb_module_get_ctx(module);
1466 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1468 /* do not manipulate our control entries */
1469 if (ldb_dn_is_special(req->op.del.dn)) {
1470 return ldb_next_request(module, req);
1473 /* Bypass the constraint checks when we do have the "RELAX" control
1475 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1476 return ldb_next_request(module, req);
1479 ac = oc_init_context(module, req);
1481 return ldb_operr(ldb);
1484 /* this looks up the entry object for fetching some important
1485 * informations (object classes, system flags...) */
1486 ret = ldb_build_search_req(&search_req, ldb,
1487 ac, req->op.del.dn, LDB_SCOPE_BASE,
1490 ac, get_search_callback,
1492 LDB_REQ_SET_LOCATION(search_req);
1493 if (ret != LDB_SUCCESS) {
1497 ac->step_fn = objectclass_do_delete;
1499 return ldb_next_request(ac->module, search_req);
1502 static int objectclass_do_delete(struct oc_context *ac)
1504 struct ldb_context *ldb;
1506 int32_t systemFlags;
1507 bool isCriticalSystemObject;
1510 ldb = ldb_module_get_ctx(ac->module);
1512 /* Check if we have a valid entry - this check is needed since
1513 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1514 if (ac->search_res == NULL) {
1515 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1516 ldb_dn_get_linearized(ac->req->op.del.dn));
1517 return LDB_ERR_NO_SUCH_OBJECT;
1520 /* DC's ntDSDSA object */
1521 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1522 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1523 ldb_dn_get_linearized(ac->req->op.del.dn));
1524 return LDB_ERR_UNWILLING_TO_PERFORM;
1527 /* DC's rIDSet object */
1528 /* Perform this check only when it does exist - this is needed in order
1529 * to don't let existing provisions break. */
1530 ret = samdb_rid_set_dn(ldb, ac, &dn);
1531 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1534 if (ret == LDB_SUCCESS) {
1535 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1537 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1538 ldb_dn_get_linearized(ac->req->op.del.dn));
1539 return LDB_ERR_UNWILLING_TO_PERFORM;
1544 /* crossRef objects regarding config, schema and default domain NCs */
1545 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1546 "crossRef") != NULL) {
1547 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1549 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1550 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1553 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1554 ldb_dn_get_linearized(ac->req->op.del.dn));
1555 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1557 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1560 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1561 ldb_dn_get_linearized(ac->req->op.del.dn));
1562 return LDB_ERR_UNWILLING_TO_PERFORM;
1569 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1571 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1572 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1573 ldb_dn_get_linearized(ac->req->op.del.dn));
1574 return LDB_ERR_UNWILLING_TO_PERFORM;
1577 /* isCriticalSystemObject - but this only applies on tree delete
1578 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1579 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1580 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1581 "isCriticalSystemObject", false);
1582 if (isCriticalSystemObject) {
1583 ldb_asprintf_errstring(ldb,
1584 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1585 ldb_dn_get_linearized(ac->req->op.del.dn));
1586 return LDB_ERR_UNWILLING_TO_PERFORM;
1590 return ldb_next_request(ac->module, ac->req);
1593 static int objectclass_init(struct ldb_module *module)
1595 struct ldb_context *ldb = ldb_module_get_ctx(module);
1598 /* Init everything else */
1599 ret = ldb_next_init(module);
1600 if (ret != LDB_SUCCESS) {
1604 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1605 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1607 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1608 if (ret != LDB_SUCCESS) {
1609 ldb_debug(ldb, LDB_DEBUG_ERROR,
1610 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1611 return ldb_operr(ldb);
1617 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1618 .name = "objectclass",
1619 .add = objectclass_add,
1620 .modify = objectclass_modify,
1621 .rename = objectclass_rename,
1622 .del = objectclass_delete,
1623 .init_context = objectclass_init
1626 int ldb_objectclass_module_init(const char *version)
1628 LDB_MODULE_CHECK_VERSION(version);
1629 return ldb_register_module(&ldb_objectclass_module_ops);