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 match the parent DN */
323 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
325 /* We need the attribute name in upper case */
326 upper_rdn_attr = strupper_talloc(*fixed_dn,
327 ldb_dn_get_rdn_name(newdn));
328 if (!upper_rdn_attr) {
329 return ldb_operr(ldb);
332 /* Create a new child */
333 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
334 return ldb_operr(ldb);
338 rdn_val = ldb_dn_get_rdn_val(newdn);
341 /* the rules for rDN length constraints are more complex than
342 this. Until we understand them we need to leave this
343 constraint out. Otherwise we break replication, as windows
344 does sometimes send us rDNs longer than 64 */
345 if (!rdn_val || rdn_val->length > 64) {
346 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
351 /* And replace it with CN=foo (we need the attribute in upper case */
352 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
356 static int objectclass_do_add(struct oc_context *ac);
358 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
360 struct ldb_context *ldb;
361 struct ldb_request *search_req;
362 struct oc_context *ac;
363 struct ldb_dn *parent_dn;
364 const struct ldb_val *val;
367 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
369 ldb = ldb_module_get_ctx(module);
371 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
373 /* do not manipulate our control entries */
374 if (ldb_dn_is_special(req->op.add.message->dn)) {
375 return ldb_next_request(module, req);
378 /* An add operation on the basedn without "NC-add" operation isn't
380 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
381 unsigned int instanceType;
383 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
385 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
386 /* When we are trying to readd the root basedn then
387 * this is denied, but with an interesting mechanism:
388 * there is generated a referral with the last
389 * component value as hostname. */
390 val = ldb_dn_get_component_val(req->op.add.message->dn,
391 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
393 return ldb_operr(ldb);
395 value = talloc_asprintf(req, "ldap://%s/%s", val->data,
396 ldb_dn_get_linearized(req->op.add.message->dn));
401 return ldb_module_send_referral(req, value);
405 ac = oc_init_context(module, req);
407 return ldb_operr(ldb);
410 /* If there isn't a parent, just go on to the add processing */
411 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
412 return objectclass_do_add(ac);
415 /* get copy of parent DN */
416 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
417 if (parent_dn == NULL) {
421 ret = ldb_build_search_req(&search_req, ldb,
422 ac, parent_dn, LDB_SCOPE_BASE,
423 "(objectClass=*)", parent_attrs,
425 ac, get_search_callback,
427 LDB_REQ_SET_LOCATION(search_req);
428 if (ret != LDB_SUCCESS) {
432 ac->step_fn = objectclass_do_add;
434 return ldb_next_request(ac->module, search_req);
439 check if this is a special RODC nTDSDSA add
441 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
442 const struct dsdb_class *objectclass)
444 struct ldb_control *rodc_control;
446 if (strcasecmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
449 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
454 rodc_control->critical = false;
458 static int objectclass_do_add(struct oc_context *ac)
460 struct ldb_context *ldb;
461 struct ldb_request *add_req;
462 struct ldb_message_element *objectclass_element, *el;
463 struct ldb_message *msg;
465 struct class_list *sorted, *current;
466 const char *rdn_name = NULL;
468 const struct dsdb_class *objectclass;
469 struct ldb_dn *objectcategory;
470 int32_t systemFlags = 0;
473 ldb = ldb_module_get_ctx(ac->module);
475 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
477 /* Check if we have a valid parent - this check is needed since
478 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
479 if (ac->search_res == NULL) {
480 unsigned int instanceType;
482 /* An add operation on partition DNs without "NC-add" operation
484 instanceType = ldb_msg_find_attr_as_uint(ac->req->op.add.message,
486 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
487 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
488 ldb_dn_get_linearized(msg->dn));
489 return LDB_ERR_NO_SUCH_OBJECT;
492 /* Don't keep any error messages - we've to add a partition */
493 ldb_set_errstring(ldb, NULL);
495 /* Fix up the DN to be in the standard form, taking
496 * particular care to match the parent DN */
497 ret = fix_dn(ldb, msg,
498 ac->req->op.add.message->dn,
499 ac->search_res->message->dn,
501 if (ret != LDB_SUCCESS) {
502 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
503 ldb_dn_get_linearized(ac->req->op.add.message->dn));
508 mem_ctx = talloc_new(ac);
509 if (mem_ctx == NULL) {
513 if (ac->schema != NULL) {
514 objectclass_element = ldb_msg_find_element(msg, "objectClass");
515 if (!objectclass_element) {
516 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
517 ldb_dn_get_linearized(msg->dn));
518 talloc_free(mem_ctx);
519 return LDB_ERR_OBJECT_CLASS_VIOLATION;
522 /* Here we do now get the "objectClass" list from the
524 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
525 objectclass_element, &sorted);
526 if (ret != LDB_SUCCESS) {
527 talloc_free(mem_ctx);
531 ldb_msg_remove_element(msg, objectclass_element);
533 /* Well, now we shouldn't find any additional "objectClass"
534 * message element (required by the AD specification). */
535 objectclass_element = ldb_msg_find_element(msg, "objectClass");
536 if (objectclass_element != NULL) {
537 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
538 ldb_dn_get_linearized(msg->dn));
539 talloc_free(mem_ctx);
540 return LDB_ERR_OBJECT_CLASS_VIOLATION;
543 /* We must completely replace the existing objectClass entry,
544 * because we need it sorted. */
545 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
546 if (ret != LDB_SUCCESS) {
547 talloc_free(mem_ctx);
551 /* Move from the linked list back into an ldb msg */
552 for (current = sorted; current; current = current->next) {
553 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
555 talloc_free(mem_ctx);
558 ret = ldb_msg_add_string(msg, "objectClass", value);
559 if (ret != LDB_SUCCESS) {
560 ldb_set_errstring(ldb,
561 "objectclass: could not re-add sorted "
562 "objectclass to modify msg");
563 talloc_free(mem_ctx);
568 talloc_free(mem_ctx);
570 /* Retrive the message again so get_last_structural_class works */
571 objectclass_element = ldb_msg_find_element(msg, "objectClass");
573 /* Make sure its valid to add an object of this type */
574 objectclass = get_last_structural_class(ac->schema,
575 objectclass_element);
576 if(objectclass == NULL) {
577 ldb_asprintf_errstring(ldb,
578 "Failed to find a structural class for %s",
579 ldb_dn_get_linearized(msg->dn));
580 return LDB_ERR_UNWILLING_TO_PERFORM;
583 rdn_name = ldb_dn_get_rdn_name(msg->dn);
584 if (objectclass->rDNAttID
585 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
586 ldb_asprintf_errstring(ldb,
587 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
588 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
589 return LDB_ERR_NAMING_VIOLATION;
592 if (objectclass->systemOnly &&
593 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
594 !check_rodc_ntdsdsa_add(ac, objectclass)) {
595 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
596 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
597 return LDB_ERR_UNWILLING_TO_PERFORM;
600 if (((strcmp(objectclass->lDAPDisplayName, "secret") == 0) ||
601 (strcmp(objectclass->lDAPDisplayName, "trustedDomain") == 0)) &&
602 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
603 ldb_asprintf_errstring(ldb, "objectClass %s is LSA-specific, rejecting creation of %s",
604 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
605 return LDB_ERR_UNWILLING_TO_PERFORM;
608 if (ac->search_res && ac->search_res->message) {
609 struct ldb_message_element *oc_el
610 = ldb_msg_find_element(ac->search_res->message, "objectClass");
612 bool allowed_class = false;
614 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
615 const struct dsdb_class *sclass;
617 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
620 /* We don't know this class? what is going on? */
623 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
624 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
625 allowed_class = true;
631 if (!allowed_class) {
632 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
633 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
634 return LDB_ERR_NAMING_VIOLATION;
638 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
640 if (objectcategory == NULL) {
641 struct dsdb_extended_dn_store_format *dn_format =
642 talloc_get_type(ldb_module_get_private(ac->module),
643 struct dsdb_extended_dn_store_format);
644 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
645 /* Strip off extended components */
646 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
647 objectclass->defaultObjectCategory);
648 value = ldb_dn_alloc_linearized(msg, dn);
651 value = talloc_strdup(msg,
652 objectclass->defaultObjectCategory);
658 ret = ldb_msg_add_string(msg, "objectCategory", value);
659 if (ret != LDB_SUCCESS) {
663 const struct dsdb_class *ocClass =
664 dsdb_class_by_cn_ldb_val(ac->schema,
665 ldb_dn_get_rdn_val(objectcategory));
666 if (ocClass != NULL) {
667 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
668 ocClass->defaultObjectCategory);
669 if (ldb_dn_compare(objectcategory, dn) != 0) {
673 talloc_free(objectcategory);
674 if (ocClass == NULL) {
675 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
676 ldb_dn_get_linearized(msg->dn));
677 return LDB_ERR_OBJECT_CLASS_VIOLATION;
681 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
682 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
686 /* There are very special rules for systemFlags, see MS-ADTS
687 * MS-ADTS 3.1.1.5.2.4 */
689 el = ldb_msg_find_element(msg, "systemFlags");
690 if ((el != NULL) && (el->num_values > 1)) {
691 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
692 ldb_dn_get_linearized(msg->dn));
693 return LDB_ERR_CONSTRAINT_VIOLATION;
696 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
698 ldb_msg_remove_attr(msg, "systemFlags");
700 /* Only the following flags may be set by a client */
701 if (ldb_request_get_control(ac->req,
702 LDB_CONTROL_RELAX_OID) == NULL) {
703 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
704 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
705 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
706 | SYSTEM_FLAG_ATTR_IS_RDN );
709 /* But the last one ("ATTR_IS_RDN") is only allowed on
710 * "attributeSchema" objects. So truncate if it does not fit. */
711 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
712 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
715 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
716 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
717 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
718 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
719 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
720 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
722 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
723 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
724 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
725 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
728 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
730 if (el || systemFlags != 0) {
731 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
733 if (ret != LDB_SUCCESS) {
738 /* make sure that "isCriticalSystemObject" is not specified! */
739 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
741 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
742 ldb_set_errstring(ldb,
743 "objectclass: 'isCriticalSystemObject' must not be specified!");
744 return LDB_ERR_UNWILLING_TO_PERFORM;
748 ret = ldb_msg_sanity_check(ldb, msg);
749 if (ret != LDB_SUCCESS) {
753 ret = ldb_build_add_req(&add_req, ldb, ac,
758 LDB_REQ_SET_LOCATION(add_req);
759 if (ret != LDB_SUCCESS) {
763 /* perform the add */
764 return ldb_next_request(ac->module, add_req);
767 static int oc_modify_callback(struct ldb_request *req,
768 struct ldb_reply *ares);
769 static int objectclass_do_mod(struct oc_context *ac);
771 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
773 struct ldb_context *ldb = ldb_module_get_ctx(module);
774 struct ldb_message_element *objectclass_element;
775 struct ldb_message *msg;
776 struct ldb_request *down_req;
777 struct oc_context *ac;
778 bool oc_changes = false;
781 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
783 /* do not manipulate our control entries */
784 if (ldb_dn_is_special(req->op.mod.message->dn)) {
785 return ldb_next_request(module, req);
788 /* As with the "real" AD we don't accept empty messages */
789 if (req->op.mod.message->num_elements == 0) {
790 ldb_set_errstring(ldb, "objectclass: modify message must have "
791 "elements/attributes!");
792 return LDB_ERR_UNWILLING_TO_PERFORM;
795 ac = oc_init_context(module, req);
797 return ldb_operr(ldb);
800 /* Without schema, there isn't much to do here */
801 if (ac->schema == NULL) {
803 return ldb_next_request(module, req);
806 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
808 return ldb_operr(ldb);
811 /* For now change everything except the objectclasses */
813 objectclass_element = ldb_msg_find_element(msg, "objectClass");
814 if (objectclass_element != NULL) {
815 ldb_msg_remove_attr(msg, "objectClass");
819 ret = ldb_build_mod_req(&down_req, ldb, ac,
822 oc_changes ? oc_modify_callback : oc_op_callback,
824 LDB_REQ_SET_LOCATION(down_req);
825 if (ret != LDB_SUCCESS) {
829 return ldb_next_request(module, down_req);
832 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
834 static const char * const attrs[] = { "objectClass", NULL };
835 struct ldb_context *ldb;
836 struct ldb_request *search_req;
837 struct oc_context *ac;
840 ac = talloc_get_type(req->context, struct oc_context);
841 ldb = ldb_module_get_ctx(ac->module);
844 return ldb_module_done(ac->req, NULL, NULL,
845 LDB_ERR_OPERATIONS_ERROR);
848 if (ares->type == LDB_REPLY_REFERRAL) {
849 return ldb_module_send_referral(ac->req, ares->referral);
852 if (ares->error != LDB_SUCCESS) {
853 return ldb_module_done(ac->req, ares->controls,
854 ares->response, ares->error);
857 if (ares->type != LDB_REPLY_DONE) {
859 return ldb_module_done(ac->req, NULL, NULL,
860 LDB_ERR_OPERATIONS_ERROR);
865 /* this looks up the real existing object for fetching some important
866 * informations (objectclasses) */
867 ret = ldb_build_search_req(&search_req, ldb,
868 ac, ac->req->op.mod.message->dn,
872 ac, get_search_callback,
874 LDB_REQ_SET_LOCATION(search_req);
875 if (ret != LDB_SUCCESS) {
876 return ldb_module_done(ac->req, NULL, NULL, ret);
879 ac->step_fn = objectclass_do_mod;
881 ret = ldb_next_request(ac->module, search_req);
882 if (ret != LDB_SUCCESS) {
883 return ldb_module_done(ac->req, NULL, NULL, ret);
889 static int objectclass_do_mod(struct oc_context *ac)
891 struct ldb_context *ldb;
892 struct ldb_request *mod_req;
894 struct ldb_message_element *oc_el_entry, *oc_el_change;
895 struct ldb_val *vals;
896 struct ldb_message *msg;
898 struct class_list *sorted, *current;
899 const struct dsdb_class *objectclass;
901 bool found, replace = false;
904 ldb = ldb_module_get_ctx(ac->module);
906 /* we should always have a valid entry when we enter here */
907 if (ac->search_res == NULL) {
908 return ldb_operr(ldb);
911 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
913 if (oc_el_entry == NULL) {
914 /* existing entry without a valid object class? */
915 return ldb_operr(ldb);
918 oc_el_change = ldb_msg_find_element(ac->req->op.mod.message,
920 if (oc_el_change == NULL) {
921 /* we should have an objectclass change operation */
922 return ldb_operr(ldb);
925 /* use a new message structure */
926 msg = ldb_msg_new(ac);
931 msg->dn = ac->req->op.mod.message->dn;
933 mem_ctx = talloc_new(ac);
934 if (mem_ctx == NULL) {
938 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
939 case LDB_FLAG_MOD_ADD:
940 /* Merge the two message elements */
941 for (i = 0; i < oc_el_change->num_values; i++) {
942 for (j = 0; j < oc_el_entry->num_values; j++) {
943 if (strcasecmp((char *)oc_el_change->values[i].data,
944 (char *)oc_el_entry->values[j].data) == 0) {
945 /* we cannot add an already existing object class */
946 talloc_free(mem_ctx);
947 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
950 /* append the new object class value - code was copied
951 * from "ldb_msg_add_value" */
952 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
954 oc_el_entry->num_values + 1);
956 talloc_free(mem_ctx);
959 oc_el_entry->values = vals;
960 oc_el_entry->values[oc_el_entry->num_values] =
961 oc_el_change->values[i];
962 ++(oc_el_entry->num_values);
965 objectclass = get_last_structural_class(ac->schema,
967 if (objectclass != NULL) {
968 /* we cannot add a new structural object class */
969 talloc_free(mem_ctx);
970 return LDB_ERR_OBJECT_CLASS_VIOLATION;
973 /* Now do the sorting */
974 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
975 oc_el_entry, &sorted);
976 if (ret != LDB_SUCCESS) {
977 talloc_free(mem_ctx);
983 case LDB_FLAG_MOD_REPLACE:
984 /* Do the sorting for the change message element */
985 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
986 oc_el_change, &sorted);
987 if (ret != LDB_SUCCESS) {
988 talloc_free(mem_ctx);
992 /* this is a replace */
997 case LDB_FLAG_MOD_DELETE:
998 /* get the actual top-most structural objectclass */
999 objectclass = get_last_structural_class(ac->schema,
1001 if (objectclass == NULL) {
1002 talloc_free(mem_ctx);
1003 return ldb_operr(ldb);
1006 /* Merge the two message elements */
1007 for (i = 0; i < oc_el_change->num_values; i++) {
1009 for (j = 0; j < oc_el_entry->num_values; j++) {
1010 if (strcasecmp((char *)oc_el_change->values[i].data,
1011 (char *)oc_el_entry->values[j].data) == 0) {
1013 /* delete the object class value -
1014 * code was copied from
1015 * "ldb_msg_remove_element" */
1016 if (j != oc_el_entry->num_values - 1) {
1017 memmove(&oc_el_entry->values[j],
1018 &oc_el_entry->values[j+1],
1019 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1021 --(oc_el_entry->num_values);
1026 /* we cannot delete a not existing object class */
1027 ldb_asprintf_errstring(ldb, "Cannot delete this %.*s ",
1028 (int)oc_el_change->values[i].length, (const char *)oc_el_change->values[i].data);
1030 talloc_free(mem_ctx);
1031 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1035 /* Make sure that the top-most structural objectclass wasn't
1038 for (i = 0; i < oc_el_entry->num_values; i++) {
1039 if (strcasecmp(objectclass->lDAPDisplayName,
1040 (char *)oc_el_entry->values[i].data) == 0) {
1041 found = true; break;
1045 talloc_free(mem_ctx);
1046 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1050 /* Now do the sorting */
1051 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1052 oc_el_entry, &sorted);
1053 if (ret != LDB_SUCCESS) {
1054 talloc_free(mem_ctx);
1061 ret = ldb_msg_add_empty(msg, "objectClass",
1062 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1063 if (ret != LDB_SUCCESS) {
1065 talloc_free(mem_ctx);
1069 /* Move from the linked list back into an ldb msg */
1070 for (current = sorted; current; current = current->next) {
1071 value = talloc_strdup(msg,
1072 current->objectclass->lDAPDisplayName);
1073 if (value == NULL) {
1074 talloc_free(mem_ctx);
1075 return ldb_oom(ldb);
1077 ret = ldb_msg_add_string(msg, "objectClass", value);
1078 if (ret != LDB_SUCCESS) {
1079 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1080 talloc_free(mem_ctx);
1085 talloc_free(mem_ctx);
1088 /* Well, on replace we are nearly done: we have to test if
1089 * the change and entry message element are identically. We
1090 * can use "ldb_msg_element_compare" since now the specified
1091 * objectclasses match for sure in case. */
1092 ret = ldb_msg_element_compare(oc_el_entry, oc_el_change);
1094 ret = ldb_msg_element_compare(oc_el_change,
1098 /* they are the same so we are done in this case */
1099 return ldb_module_done(ac->req, NULL, NULL,
1102 /* they're not exactly the same */
1103 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1107 /* in the other cases we have the real change left to do */
1109 ret = ldb_msg_sanity_check(ldb, msg);
1110 if (ret != LDB_SUCCESS) {
1114 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1119 LDB_REQ_SET_LOCATION(mod_req);
1120 if (ret != LDB_SUCCESS) {
1124 return ldb_next_request(ac->module, mod_req);
1127 static int objectclass_do_rename(struct oc_context *ac);
1129 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1131 static const char * const attrs[] = { "objectClass", NULL };
1132 struct ldb_context *ldb;
1133 struct ldb_request *search_req;
1134 struct oc_context *ac;
1135 struct ldb_dn *parent_dn;
1138 ldb = ldb_module_get_ctx(module);
1140 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1142 /* do not manipulate our control entries */
1143 if (ldb_dn_is_special(req->op.rename.newdn)) {
1144 return ldb_next_request(module, req);
1147 ac = oc_init_context(module, req);
1149 return ldb_operr(ldb);
1152 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1153 if (parent_dn == NULL) {
1154 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1155 ldb_dn_get_linearized(req->op.rename.olddn));
1156 return LDB_ERR_NO_SUCH_OBJECT;
1159 /* this looks up the parent object for fetching some important
1160 * informations (objectclasses, DN normalisation...) */
1161 ret = ldb_build_search_req(&search_req, ldb,
1162 ac, parent_dn, LDB_SCOPE_BASE,
1165 ac, get_search_callback,
1167 LDB_REQ_SET_LOCATION(search_req);
1168 if (ret != LDB_SUCCESS) {
1172 /* we have to add the show recycled control, as otherwise DRS
1173 deletes will be refused as we will think the target parent
1175 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1178 if (ret != LDB_SUCCESS) {
1182 ac->step_fn = objectclass_do_rename;
1184 return ldb_next_request(ac->module, search_req);
1187 static int objectclass_do_rename2(struct oc_context *ac);
1189 static int objectclass_do_rename(struct oc_context *ac)
1191 static const char * const attrs[] = { "objectClass", NULL };
1192 struct ldb_context *ldb;
1193 struct ldb_request *search_req;
1196 ldb = ldb_module_get_ctx(ac->module);
1198 /* Check if we have a valid parent - this check is needed since
1199 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1200 if (ac->search_res == NULL) {
1201 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1202 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1203 return LDB_ERR_OTHER;
1206 /* now assign "search_res2" to the parent entry to have "search_res"
1207 * free for another lookup */
1208 ac->search_res2 = ac->search_res;
1209 ac->search_res = NULL;
1211 /* this looks up the real existing object for fetching some important
1212 * informations (objectclasses) */
1213 ret = ldb_build_search_req(&search_req, ldb,
1214 ac, ac->req->op.rename.olddn,
1218 ac, get_search_callback,
1220 LDB_REQ_SET_LOCATION(search_req);
1221 if (ret != LDB_SUCCESS) {
1225 ac->step_fn = objectclass_do_rename2;
1227 return ldb_next_request(ac->module, search_req);
1230 static int objectclass_do_rename2(struct oc_context *ac)
1232 struct ldb_context *ldb;
1233 struct ldb_request *rename_req;
1234 struct ldb_dn *fixed_dn;
1237 ldb = ldb_module_get_ctx(ac->module);
1239 /* Check if we have a valid entry - this check is needed since
1240 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1241 if (ac->search_res == NULL) {
1242 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1243 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1244 return LDB_ERR_NO_SUCH_OBJECT;
1247 if (ac->schema != NULL) {
1248 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1249 const struct dsdb_class *objectclass;
1250 const char *rdn_name;
1251 bool allowed_class = false;
1254 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1256 if (oc_el_entry == NULL) {
1257 /* existing entry without a valid object class? */
1258 return ldb_operr(ldb);
1260 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1261 if (objectclass == NULL) {
1262 /* existing entry without a valid object class? */
1263 return ldb_operr(ldb);
1266 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1267 if ((objectclass->rDNAttID != NULL) &&
1268 (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1269 ldb_asprintf_errstring(ldb,
1270 "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1272 objectclass->lDAPDisplayName,
1273 objectclass->rDNAttID);
1274 return LDB_ERR_UNWILLING_TO_PERFORM;
1277 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1279 if (oc_el_parent == NULL) {
1280 /* existing entry without a valid object class? */
1281 return ldb_operr(ldb);
1284 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1285 const struct dsdb_class *sclass;
1287 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1288 &oc_el_parent->values[i]);
1290 /* We don't know this class? what is going on? */
1293 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1294 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1295 allowed_class = true;
1301 if (!allowed_class) {
1302 ldb_asprintf_errstring(ldb,
1303 "objectclass: structural objectClass %s is not a valid child class for %s",
1304 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1305 return LDB_ERR_NAMING_VIOLATION;
1309 /* Ensure we are not trying to rename it to be a child of itself */
1310 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1311 ac->req->op.rename.newdn) == 0) &&
1312 (ldb_dn_compare(ac->req->op.rename.olddn,
1313 ac->req->op.rename.newdn) != 0)) {
1314 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1315 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1316 return LDB_ERR_UNWILLING_TO_PERFORM;
1319 /* Fix up the DN to be in the standard form, taking
1320 * particular care to match the parent DN */
1321 ret = fix_dn(ldb, ac,
1322 ac->req->op.rename.newdn,
1323 ac->search_res2->message->dn,
1325 if (ret != LDB_SUCCESS) {
1326 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1327 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1332 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1333 ac->req->op.rename.olddn, fixed_dn,
1337 LDB_REQ_SET_LOCATION(rename_req);
1338 if (ret != LDB_SUCCESS) {
1342 /* perform the rename */
1343 return ldb_next_request(ac->module, rename_req);
1346 static int objectclass_do_delete(struct oc_context *ac);
1348 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1350 static const char * const attrs[] = { "nCName", "objectClass",
1352 "isCriticalSystemObject", NULL };
1353 struct ldb_context *ldb;
1354 struct ldb_request *search_req;
1355 struct oc_context *ac;
1358 ldb = ldb_module_get_ctx(module);
1360 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1362 /* do not manipulate our control entries */
1363 if (ldb_dn_is_special(req->op.del.dn)) {
1364 return ldb_next_request(module, req);
1367 /* Bypass the constraint checks when we do have the "RELAX" control
1369 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1370 return ldb_next_request(module, req);
1373 ac = oc_init_context(module, req);
1375 return ldb_operr(ldb);
1378 /* this looks up the entry object for fetching some important
1379 * informations (object classes, system flags...) */
1380 ret = ldb_build_search_req(&search_req, ldb,
1381 ac, req->op.del.dn, LDB_SCOPE_BASE,
1384 ac, get_search_callback,
1386 LDB_REQ_SET_LOCATION(search_req);
1387 if (ret != LDB_SUCCESS) {
1391 ac->step_fn = objectclass_do_delete;
1393 return ldb_next_request(ac->module, search_req);
1396 static int objectclass_do_delete(struct oc_context *ac)
1398 struct ldb_context *ldb;
1400 int32_t systemFlags;
1401 bool isCriticalSystemObject;
1404 ldb = ldb_module_get_ctx(ac->module);
1406 /* Check if we have a valid entry - this check is needed since
1407 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1408 if (ac->search_res == NULL) {
1409 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1410 ldb_dn_get_linearized(ac->req->op.del.dn));
1411 return LDB_ERR_NO_SUCH_OBJECT;
1414 /* DC's ntDSDSA object */
1415 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1416 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1417 ldb_dn_get_linearized(ac->req->op.del.dn));
1418 return LDB_ERR_UNWILLING_TO_PERFORM;
1421 /* DC's rIDSet object */
1422 /* Perform this check only when it does exist - this is needed in order
1423 * to don't let existing provisions break. */
1424 ret = samdb_rid_set_dn(ldb, ac, &dn);
1425 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1428 if (ret == LDB_SUCCESS) {
1429 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1431 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1432 ldb_dn_get_linearized(ac->req->op.del.dn));
1433 return LDB_ERR_UNWILLING_TO_PERFORM;
1438 /* crossRef objects regarding config, schema and default domain NCs */
1439 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1440 "crossRef") != NULL) {
1441 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1443 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1444 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1447 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1448 ldb_dn_get_linearized(ac->req->op.del.dn));
1449 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1451 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1454 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1455 ldb_dn_get_linearized(ac->req->op.del.dn));
1456 return LDB_ERR_UNWILLING_TO_PERFORM;
1463 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1465 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1466 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1467 ldb_dn_get_linearized(ac->req->op.del.dn));
1468 return LDB_ERR_UNWILLING_TO_PERFORM;
1471 /* isCriticalSystemObject - but this only applies on tree delete
1472 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1473 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1474 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1475 "isCriticalSystemObject", false);
1476 if (isCriticalSystemObject) {
1477 ldb_asprintf_errstring(ldb,
1478 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1479 ldb_dn_get_linearized(ac->req->op.del.dn));
1480 return LDB_ERR_UNWILLING_TO_PERFORM;
1484 return ldb_next_request(ac->module, ac->req);
1487 static int objectclass_init(struct ldb_module *module)
1489 struct ldb_context *ldb = ldb_module_get_ctx(module);
1492 /* Init everything else */
1493 ret = ldb_next_init(module);
1494 if (ret != LDB_SUCCESS) {
1498 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1499 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1501 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1502 if (ret != LDB_SUCCESS) {
1503 ldb_debug(ldb, LDB_DEBUG_ERROR,
1504 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1505 return ldb_operr(ldb);
1511 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1512 .name = "objectclass",
1513 .add = objectclass_add,
1514 .modify = objectclass_modify,
1515 .rename = objectclass_rename,
1516 .del = objectclass_delete,
1517 .init_context = objectclass_init