4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Component: objectClass sorting module
27 * - sort the objectClass attribute into the class
29 * - fix DNs and attributes into 'standard' case
30 * - Add objectCategory and ntSecurityDescriptor defaults
32 * Author: Andrew Bartlett
37 #include "ldb_module.h"
38 #include "dlinklist.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "librpc/ndr/libndr.h"
41 #include "librpc/gen_ndr/ndr_security.h"
42 #include "libcli/security/security.h"
43 #include "auth/auth.h"
44 #include "param/param.h"
45 #include "../libds/common/flags.h"
50 struct ldb_module *module;
51 struct ldb_request *req;
53 struct ldb_reply *search_res;
55 int (*step_fn)(struct oc_context *);
59 struct class_list *prev, *next;
60 const struct dsdb_class *objectclass;
63 static struct oc_context *oc_init_context(struct ldb_module *module,
64 struct ldb_request *req)
66 struct ldb_context *ldb;
67 struct oc_context *ac;
69 ldb = ldb_module_get_ctx(module);
71 ac = talloc_zero(req, struct oc_context);
73 ldb_set_errstring(ldb, "Out of Memory");
83 static int objectclass_do_add(struct oc_context *ac);
85 /* Sort objectClasses into correct order, and validate that all
86 * objectClasses specified actually exist in the schema
89 static int objectclass_sort(struct ldb_module *module,
90 const struct dsdb_schema *schema,
92 struct ldb_message_element *objectclass_element,
93 struct class_list **sorted_out)
95 struct ldb_context *ldb;
96 unsigned int i, lowest;
97 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
99 ldb = ldb_module_get_ctx(module);
103 * We work on 4 different 'bins' (implemented here as linked lists):
105 * * sorted: the eventual list, in the order we wish to push
106 * into the database. This is the only ordered list.
108 * * parent_class: The current parent class 'bin' we are
109 * trying to find subclasses for
111 * * subclass: The subclasses we have found so far
113 * * unsorted: The remaining objectClasses
115 * The process is a matter of filtering objectClasses up from
116 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
118 * We start with 'top' (found and promoted to parent_class
119 * initially). Then we find (in unsorted) all the direct
120 * subclasses of 'top'. parent_classes is concatenated onto
121 * the end of 'sorted', and subclass becomes the list in
124 * We then repeat, until we find no more subclasses. Any left
125 * over classes are added to the end.
129 /* Firstly, dump all the objectClass elements into the
130 * unsorted bin, except for 'top', which is special */
131 for (i=0; i < objectclass_element->num_values; i++) {
132 current = talloc(mem_ctx, struct class_list);
135 return LDB_ERR_OPERATIONS_ERROR;
137 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
138 if (!current->objectclass) {
139 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
140 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
141 /* This looks weird, but windows apparently returns this for invalid objectClass values */
142 return LDB_ERR_NO_SUCH_ATTRIBUTE;
143 } else if (current->objectclass->isDefunct) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
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;
150 /* Don't add top to list, we will do that later */
151 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
152 DLIST_ADD_END(unsorted, current, struct class_list *);
156 /* Add top here, to prevent duplicates */
157 current = talloc(mem_ctx, struct class_list);
158 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
159 DLIST_ADD_END(sorted, current, struct class_list *);
162 /* For each object: find parent chain */
163 for (current = unsorted; schema && current; current = current->next) {
164 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
165 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
169 /* If we didn't get to the end of the list, we need to add this parent */
170 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
174 new_parent = talloc(mem_ctx, struct class_list);
175 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
176 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
182 current_lowest = NULL;
183 for (current = unsorted; schema && current; current = current->next) {
184 if(current->objectclass->subClass_order < lowest) {
185 current_lowest = current;
186 lowest = current->objectclass->subClass_order;
190 if(current_lowest != NULL) {
191 DLIST_REMOVE(unsorted,current_lowest);
192 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
198 *sorted_out = sorted;
203 /* If we don't have schema yet, then just merge the lists again */
204 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
205 *sorted_out = sorted;
209 /* This shouldn't happen, and would break MMC, perhaps there
210 * was no 'top', a conflict in the objectClasses or some other
213 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
214 return LDB_ERR_OBJECT_CLASS_VIOLATION;
217 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
219 struct ldb_context *ldb;
220 struct oc_context *ac;
223 ac = talloc_get_type(req->context, struct oc_context);
224 ldb = ldb_module_get_ctx(ac->module);
227 return ldb_module_done(ac->req, NULL, NULL,
228 LDB_ERR_OPERATIONS_ERROR);
230 if (ares->error != LDB_SUCCESS &&
231 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
232 return ldb_module_done(ac->req, ares->controls,
233 ares->response, ares->error);
236 ldb_reset_err_string(ldb);
238 switch (ares->type) {
239 case LDB_REPLY_ENTRY:
240 if (ac->search_res != NULL) {
241 ldb_set_errstring(ldb, "Too many results");
243 return ldb_module_done(ac->req, NULL, NULL,
244 LDB_ERR_OPERATIONS_ERROR);
247 ac->search_res = talloc_steal(ac, ares);
250 case LDB_REPLY_REFERRAL:
257 ret = ac->step_fn(ac);
258 if (ret != LDB_SUCCESS) {
259 return ldb_module_done(ac->req, NULL, NULL, ret);
267 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
269 struct oc_context *ac;
271 ac = talloc_get_type(req->context, struct oc_context);
274 return ldb_module_done(ac->req, NULL, NULL,
275 LDB_ERR_OPERATIONS_ERROR);
277 if (ares->error != LDB_SUCCESS) {
278 return ldb_module_done(ac->req, ares->controls,
279 ares->response, ares->error);
282 if (ares->type != LDB_REPLY_DONE) {
284 return ldb_module_done(ac->req, NULL, NULL,
285 LDB_ERR_OPERATIONS_ERROR);
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
294 This should mean that if the parent is:
295 CN=Users,DC=samba,DC=example,DC=com
296 and a proposed child is
297 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
299 The resulting DN should be:
301 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
304 static int fix_dn(TALLOC_CTX *mem_ctx,
305 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
306 struct ldb_dn **fixed_dn)
308 char *upper_rdn_attr;
309 const struct ldb_val *rdn_val;
311 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
312 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
314 /* We need the attribute name in upper case */
315 upper_rdn_attr = strupper_talloc(*fixed_dn,
316 ldb_dn_get_rdn_name(newdn));
317 if (!upper_rdn_attr) {
318 return LDB_ERR_OPERATIONS_ERROR;
321 /* Create a new child */
322 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
323 return LDB_ERR_OPERATIONS_ERROR;
327 rdn_val = ldb_dn_get_rdn_val(newdn);
330 /* the rules for rDN length constraints are more complex than
331 this. Until we understand them we need to leave this
332 constraint out. Otherwise we break replication, as windows
333 does sometimes send us rDNs longer than 64 */
334 if (!rdn_val || rdn_val->length > 64) {
335 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
340 /* And replace it with CN=foo (we need the attribute in upper case */
341 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
344 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
345 static int fix_check_attributes(struct ldb_context *ldb,
346 const struct dsdb_schema *schema,
347 struct ldb_message *msg,
348 enum ldb_request_type op)
351 for (i=0; i < msg->num_elements; i++) {
352 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
353 /* Add in a very special case for 'clearTextPassword',
354 * which is used for internal processing only, and is
355 * not presented in the schema */
357 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
358 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
359 /* Apparently Windows sends exactly this behaviour */
360 return LDB_ERR_NO_SUCH_ATTRIBUTE;
363 msg->elements[i].name = attribute->lDAPDisplayName;
365 /* We have to deny write operations on constructed attributes */
366 if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
367 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
369 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
371 return LDB_ERR_CONSTRAINT_VIOLATION;
381 static int objectclass_do_add(struct oc_context *ac);
383 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
385 struct ldb_context *ldb;
386 struct ldb_request *search_req;
387 struct oc_context *ac;
388 struct ldb_dn *parent_dn;
390 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
392 ldb = ldb_module_get_ctx(module);
394 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
396 /* do not manipulate our control entries */
397 if (ldb_dn_is_special(req->op.add.message->dn)) {
398 return ldb_next_request(module, req);
401 /* the objectClass must be specified on add */
402 if (ldb_msg_find_element(req->op.add.message,
403 "objectClass") == NULL) {
404 return LDB_ERR_OBJECT_CLASS_VIOLATION;
407 ac = oc_init_context(module, req);
409 return LDB_ERR_OPERATIONS_ERROR;
412 /* If there isn't a parent, just go on to the add processing */
413 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
414 return objectclass_do_add(ac);
417 /* get copy of parent DN */
418 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
419 if (parent_dn == NULL) {
421 return LDB_ERR_OPERATIONS_ERROR;
424 ret = ldb_build_search_req(&search_req, ldb,
425 ac, parent_dn, LDB_SCOPE_BASE,
426 "(objectClass=*)", parent_attrs,
428 ac, get_search_callback,
430 if (ret != LDB_SUCCESS) {
433 talloc_steal(search_req, parent_dn);
435 ac->step_fn = objectclass_do_add;
437 return ldb_next_request(ac->module, search_req);
440 static int objectclass_do_add(struct oc_context *ac)
442 struct ldb_context *ldb;
443 const struct dsdb_schema *schema;
444 struct ldb_request *add_req;
446 struct ldb_message_element *objectclass_element, *el;
447 struct ldb_message *msg;
449 struct class_list *sorted, *current;
451 const struct dsdb_class *objectclass;
452 int32_t systemFlags = 0;
453 const char *rdn_name = NULL;
455 ldb = ldb_module_get_ctx(ac->module);
456 schema = dsdb_get_schema(ldb, ac);
458 mem_ctx = talloc_new(ac);
459 if (mem_ctx == NULL) {
461 return LDB_ERR_OPERATIONS_ERROR;
464 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
466 /* Check we have a valid parent */
467 if (ac->search_res == NULL) {
468 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
470 /* Allow the tree to be started */
472 /* but don't keep any error string, it's meaningless */
473 ldb_set_errstring(ldb, NULL);
475 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
476 ldb_dn_get_linearized(msg->dn));
477 talloc_free(mem_ctx);
478 return LDB_ERR_NO_SUCH_OBJECT;
482 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
484 ac->req->op.add.message->dn,
485 ac->search_res->message->dn,
488 if (ret != LDB_SUCCESS) {
489 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
490 ldb_dn_get_linearized(ac->req->op.add.message->dn));
491 talloc_free(mem_ctx);
497 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
498 if (ret != LDB_SUCCESS) {
499 talloc_free(mem_ctx);
503 /* This is now the objectClass list from the database */
504 objectclass_element = ldb_msg_find_element(msg, "objectClass");
506 if (!objectclass_element) {
507 /* Where did it go? bail now... */
508 talloc_free(mem_ctx);
509 return LDB_ERR_OPERATIONS_ERROR;
511 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
512 if (ret != LDB_SUCCESS) {
513 talloc_free(mem_ctx);
517 ldb_msg_remove_attr(msg, "objectClass");
518 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
520 if (ret != LDB_SUCCESS) {
521 talloc_free(mem_ctx);
525 /* We must completely replace the existing objectClass entry,
526 * because we need it sorted */
528 /* Move from the linked list back into an ldb msg */
529 for (current = sorted; current; current = current->next) {
530 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
533 talloc_free(mem_ctx);
534 return LDB_ERR_OPERATIONS_ERROR;
536 ret = ldb_msg_add_string(msg, "objectClass", value);
537 if (ret != LDB_SUCCESS) {
538 ldb_set_errstring(ldb,
539 "objectclass: could not re-add sorted "
540 "objectclass to modify msg");
541 talloc_free(mem_ctx);
546 /* Retrive the message again so get_last_structural_class works */
547 objectclass_element = ldb_msg_find_element(msg, "objectClass");
549 /* Make sure its valid to add an object of this type */
550 objectclass = get_last_structural_class(schema,objectclass_element);
551 if(objectclass == NULL) {
552 ldb_asprintf_errstring(ldb,
553 "Failed to find a structural class for %s",
554 ldb_dn_get_linearized(msg->dn));
555 return LDB_ERR_NAMING_VIOLATION;
558 rdn_name = ldb_dn_get_rdn_name(msg->dn);
559 if (objectclass->rDNAttID
560 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
561 ldb_asprintf_errstring(ldb,
562 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
563 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
564 return LDB_ERR_NAMING_VIOLATION;
567 if (ac->search_res && ac->search_res->message) {
568 struct ldb_message_element *oc_el
569 = ldb_msg_find_element(ac->search_res->message, "objectClass");
571 bool allowed_class = false;
573 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
574 const struct dsdb_class *sclass;
576 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
578 /* We don't know this class? what is going on? */
581 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
582 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
583 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
584 allowed_class = true;
589 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
590 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
591 allowed_class = true;
598 if (!allowed_class) {
599 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
600 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
601 return LDB_ERR_NAMING_VIOLATION;
605 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
606 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
607 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
608 return LDB_ERR_UNWILLING_TO_PERFORM;
611 if (!ldb_msg_find_element(msg, "objectCategory")) {
612 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
613 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
614 /* Strip off extended components */
615 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
616 value = ldb_dn_alloc_linearized(msg, dn);
619 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
623 talloc_free(mem_ctx);
624 return LDB_ERR_OPERATIONS_ERROR;
626 ldb_msg_add_string(msg, "objectCategory", value);
628 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
629 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
633 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
634 el = ldb_msg_find_element(msg, "systemFlags");
636 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
639 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
640 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
641 ldb_msg_remove_element(msg, el);
644 /* This flag is only allowed on attributeSchema objects */
645 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
646 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
649 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
650 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
651 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
652 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
653 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
654 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
656 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
657 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
658 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
659 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
662 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
664 if (el || systemFlags != 0) {
665 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
669 talloc_free(mem_ctx);
670 ret = ldb_msg_sanity_check(ldb, msg);
673 if (ret != LDB_SUCCESS) {
677 ret = ldb_build_add_req(&add_req, ldb, ac,
682 if (ret != LDB_SUCCESS) {
686 /* perform the add */
687 return ldb_next_request(ac->module, add_req);
690 static int oc_modify_callback(struct ldb_request *req,
691 struct ldb_reply *ares);
692 static int objectclass_do_mod(struct oc_context *ac);
694 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
696 struct ldb_context *ldb = ldb_module_get_ctx(module);
697 struct ldb_message_element *objectclass_element;
698 struct ldb_message *msg;
699 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
700 struct class_list *sorted, *current;
701 struct ldb_request *down_req;
702 struct oc_context *ac;
707 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
709 /* do not manipulate our control entries */
710 if (ldb_dn_is_special(req->op.mod.message->dn)) {
711 return ldb_next_request(module, req);
714 /* Without schema, there isn't much to do here */
716 return ldb_next_request(module, req);
719 /* As with the "real" AD we don't accept empty messages */
720 if (req->op.mod.message->num_elements == 0) {
721 ldb_set_errstring(ldb, "objectclass: modify message must have "
722 "elements/attributes!");
723 return LDB_ERR_UNWILLING_TO_PERFORM;
726 ac = oc_init_context(module, req);
729 return LDB_ERR_OPERATIONS_ERROR;
732 if (!talloc_reference(ac, schema)) {
734 return LDB_ERR_OPERATIONS_ERROR;
737 /* If no part of this touches the objectClass, then we don't
738 * need to make any changes. */
739 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
741 /* If the only operation is the deletion of the objectClass
742 * then go on with just fixing the attribute case */
743 if (!objectclass_element) {
744 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
746 return LDB_ERR_OPERATIONS_ERROR;
749 ret = fix_check_attributes(ldb, schema, msg, req->operation);
750 if (ret != LDB_SUCCESS) {
754 ret = ldb_build_mod_req(&down_req, ldb, ac,
759 if (ret != LDB_SUCCESS) {
763 /* go on with the call chain */
764 return ldb_next_request(module, down_req);
767 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
768 case LDB_FLAG_MOD_DELETE:
769 if (objectclass_element->num_values == 0) {
770 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
774 case LDB_FLAG_MOD_REPLACE:
775 mem_ctx = talloc_new(ac);
776 if (mem_ctx == NULL) {
777 return LDB_ERR_OPERATIONS_ERROR;
780 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
782 talloc_free(mem_ctx);
783 return LDB_ERR_OPERATIONS_ERROR;
786 ret = fix_check_attributes(ldb, schema, msg, req->operation);
787 if (ret != LDB_SUCCESS) {
788 talloc_free(mem_ctx);
792 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
793 if (ret != LDB_SUCCESS) {
794 talloc_free(mem_ctx);
798 /* We must completely replace the existing objectClass entry,
799 * because we need it sorted */
801 ldb_msg_remove_attr(msg, "objectClass");
802 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
804 if (ret != LDB_SUCCESS) {
805 talloc_free(mem_ctx);
809 /* Move from the linked list back into an ldb msg */
810 for (current = sorted; current; current = current->next) {
811 /* copy the value as this string is on the schema
812 * context and we can't rely on it not changing
813 * before the operation is over */
814 value = talloc_strdup(msg,
815 current->objectclass->lDAPDisplayName);
818 talloc_free(mem_ctx);
819 return LDB_ERR_OPERATIONS_ERROR;
821 ret = ldb_msg_add_string(msg, "objectClass", value);
822 if (ret != LDB_SUCCESS) {
823 ldb_set_errstring(ldb,
824 "objectclass: could not re-add sorted "
825 "objectclass to modify msg");
826 talloc_free(mem_ctx);
831 talloc_free(mem_ctx);
833 ret = ldb_msg_sanity_check(ldb, msg);
834 if (ret != LDB_SUCCESS) {
838 ret = ldb_build_mod_req(&down_req, ldb, ac,
843 if (ret != LDB_SUCCESS) {
847 /* go on with the call chain */
848 return ldb_next_request(module, down_req);
851 /* This isn't the default branch of the switch, but a 'in any
852 * other case'. When a delete isn't for all objectClasses for
856 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
859 return LDB_ERR_OPERATIONS_ERROR;
862 ret = fix_check_attributes(ldb, schema, msg, req->operation);
863 if (ret != LDB_SUCCESS) {
868 ret = ldb_build_mod_req(&down_req, ldb, ac,
871 ac, oc_modify_callback,
873 if (ret != LDB_SUCCESS) {
877 return ldb_next_request(module, down_req);
880 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
882 struct ldb_context *ldb;
883 static const char * const attrs[] = { "objectClass", NULL };
884 struct ldb_request *search_req;
885 struct oc_context *ac;
888 ac = talloc_get_type(req->context, struct oc_context);
889 ldb = ldb_module_get_ctx(ac->module);
892 return ldb_module_done(ac->req, NULL, NULL,
893 LDB_ERR_OPERATIONS_ERROR);
895 if (ares->error != LDB_SUCCESS) {
896 return ldb_module_done(ac->req, ares->controls,
897 ares->response, ares->error);
900 if (ares->type != LDB_REPLY_DONE) {
902 return ldb_module_done(ac->req, NULL, NULL,
903 LDB_ERR_OPERATIONS_ERROR);
908 ret = ldb_build_search_req(&search_req, ldb, ac,
909 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
912 ac, get_search_callback,
914 if (ret != LDB_SUCCESS) {
915 return ldb_module_done(ac->req, NULL, NULL, ret);
918 ac->step_fn = objectclass_do_mod;
920 ret = ldb_next_request(ac->module, search_req);
921 if (ret != LDB_SUCCESS) {
922 return ldb_module_done(ac->req, NULL, NULL, ret);
927 static int objectclass_do_mod(struct oc_context *ac)
929 struct ldb_context *ldb;
930 const struct dsdb_schema *schema;
931 struct ldb_request *mod_req;
933 struct ldb_message_element *objectclass_element;
934 struct ldb_message *msg;
936 struct class_list *sorted, *current;
939 ldb = ldb_module_get_ctx(ac->module);
941 if (ac->search_res == NULL) {
942 return LDB_ERR_OPERATIONS_ERROR;
944 schema = dsdb_get_schema(ldb, ac);
946 mem_ctx = talloc_new(ac);
947 if (mem_ctx == NULL) {
948 return LDB_ERR_OPERATIONS_ERROR;
951 /* use a new message structure */
952 msg = ldb_msg_new(ac);
954 ldb_set_errstring(ldb,
955 "objectclass: could not create new modify msg");
956 talloc_free(mem_ctx);
957 return LDB_ERR_OPERATIONS_ERROR;
960 /* This is now the objectClass list from the database */
961 objectclass_element = ldb_msg_find_element(ac->search_res->message,
963 if (!objectclass_element) {
964 /* Where did it go? bail now... */
965 talloc_free(mem_ctx);
966 return LDB_ERR_OPERATIONS_ERROR;
970 msg->dn = ac->req->op.mod.message->dn;
972 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
973 if (ret != LDB_SUCCESS) {
977 /* We must completely replace the existing objectClass entry.
978 * We could do a constrained add/del, but we are meant to be
979 * in a transaction... */
981 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
982 if (ret != LDB_SUCCESS) {
983 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
984 talloc_free(mem_ctx);
988 /* Move from the linked list back into an ldb msg */
989 for (current = sorted; current; current = current->next) {
990 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
993 return LDB_ERR_OPERATIONS_ERROR;
995 ret = ldb_msg_add_string(msg, "objectClass", value);
996 if (ret != LDB_SUCCESS) {
997 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
998 talloc_free(mem_ctx);
1003 ret = ldb_msg_sanity_check(ldb, msg);
1004 if (ret != LDB_SUCCESS) {
1005 talloc_free(mem_ctx);
1009 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1014 if (ret != LDB_SUCCESS) {
1015 talloc_free(mem_ctx);
1019 talloc_free(mem_ctx);
1020 /* perform the modify */
1021 return ldb_next_request(ac->module, mod_req);
1024 static int objectclass_do_rename(struct oc_context *ac);
1026 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1028 static const char * const attrs[] = { NULL };
1029 struct ldb_context *ldb;
1030 struct ldb_request *search_req;
1031 struct oc_context *ac;
1032 struct ldb_dn *parent_dn;
1035 ldb = ldb_module_get_ctx(module);
1037 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1039 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1040 return ldb_next_request(module, req);
1043 /* Firstly ensure we are not trying to rename it to be a child of itself */
1044 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1045 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1046 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1047 ldb_dn_get_linearized(req->op.rename.olddn));
1048 return LDB_ERR_UNWILLING_TO_PERFORM;
1051 ac = oc_init_context(module, req);
1053 return LDB_ERR_OPERATIONS_ERROR;
1056 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1057 if (parent_dn == NULL) {
1059 return LDB_ERR_OPERATIONS_ERROR;
1063 it makes a search request, looking for the parent DN to fix up the new DN
1064 to a standard one, at objectclass_do_rename()
1066 ret = ldb_build_search_req(&search_req, ldb,
1067 ac, parent_dn, LDB_SCOPE_BASE,
1070 ac, get_search_callback,
1072 if (ret != LDB_SUCCESS) {
1076 /* we have to add the show deleted control, as otherwise DRS
1077 deletes will be refused as we will think the target parent
1079 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1081 if (ret != LDB_SUCCESS) {
1085 ac->step_fn = objectclass_do_rename;
1087 return ldb_next_request(ac->module, search_req);
1092 static int objectclass_do_rename(struct oc_context *ac)
1094 struct ldb_context *ldb;
1095 struct ldb_request *rename_req;
1096 struct ldb_dn *fixed_dn;
1099 ldb = ldb_module_get_ctx(ac->module);
1101 /* Check we have a valid parent */
1102 if (ac->search_res == NULL) {
1103 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1104 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1105 return LDB_ERR_UNWILLING_TO_PERFORM;
1108 /* Fix up the DN to be in the standard form,
1109 * taking particular care to match the parent DN */
1111 ac->req->op.rename.newdn,
1112 ac->search_res->message->dn,
1114 if (ret != LDB_SUCCESS) {
1118 /* TODO: Check this is a valid child to this parent,
1119 * by reading the allowedChildClasses and
1120 * allowedChildClasssesEffective attributes */
1122 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1123 ac->req->op.rename.olddn, fixed_dn,
1127 if (ret != LDB_SUCCESS) {
1131 /* perform the rename */
1132 return ldb_next_request(ac->module, rename_req);
1135 static int objectclass_init(struct ldb_module *module)
1137 struct ldb_context *ldb = ldb_module_get_ctx(module);
1139 /* Init everything else */
1140 ret = ldb_next_init(module);
1141 if (ret != LDB_SUCCESS) {
1145 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1146 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1151 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1152 .name = "objectclass",
1153 .add = objectclass_add,
1154 .modify = objectclass_modify,
1155 .rename = objectclass_rename,
1156 .init_context = objectclass_init