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 "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"
52 struct ldb_module *module;
53 struct ldb_request *req;
55 struct ldb_reply *search_res;
57 int (*step_fn)(struct oc_context *);
61 struct class_list *prev, *next;
62 const struct dsdb_class *objectclass;
65 static struct oc_context *oc_init_context(struct ldb_module *module,
66 struct ldb_request *req)
68 struct ldb_context *ldb;
69 struct oc_context *ac;
71 ldb = ldb_module_get_ctx(module);
73 ac = talloc_zero(req, struct oc_context);
85 static int objectclass_do_add(struct oc_context *ac);
87 /* Sort objectClasses into correct order, and validate that all
88 * objectClasses specified actually exist in the schema
91 static int objectclass_sort(struct ldb_module *module,
92 const struct dsdb_schema *schema,
94 struct ldb_message_element *objectclass_element,
95 struct class_list **sorted_out)
97 struct ldb_context *ldb;
98 unsigned int i, lowest;
99 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
101 ldb = ldb_module_get_ctx(module);
105 * We work on 4 different 'bins' (implemented here as linked lists):
107 * * sorted: the eventual list, in the order we wish to push
108 * into the database. This is the only ordered list.
110 * * parent_class: The current parent class 'bin' we are
111 * trying to find subclasses for
113 * * subclass: The subclasses we have found so far
115 * * unsorted: The remaining objectClasses
117 * The process is a matter of filtering objectClasses up from
118 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
120 * We start with 'top' (found and promoted to parent_class
121 * initially). Then we find (in unsorted) all the direct
122 * subclasses of 'top'. parent_classes is concatenated onto
123 * the end of 'sorted', and subclass becomes the list in
126 * We then repeat, until we find no more subclasses. Any left
127 * over classes are added to the end.
131 /* Firstly, dump all the objectClass elements into the
132 * unsorted bin, except for 'top', which is special */
133 for (i=0; i < objectclass_element->num_values; i++) {
134 current = talloc(mem_ctx, struct class_list);
137 return LDB_ERR_OPERATIONS_ERROR;
139 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
140 if (!current->objectclass) {
141 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
142 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
143 /* This looks weird, but windows apparently returns this for invalid objectClass values */
144 return LDB_ERR_NO_SUCH_ATTRIBUTE;
145 } else if (current->objectclass->isDefunct) {
146 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
147 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
148 /* This looks weird, but windows apparently returns this for invalid objectClass values */
149 return LDB_ERR_NO_SUCH_ATTRIBUTE;
152 /* Don't add top to list, we will do that later */
153 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
154 DLIST_ADD_END(unsorted, current, struct class_list *);
158 /* Add top here, to prevent duplicates */
159 current = talloc(mem_ctx, struct class_list);
160 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
161 DLIST_ADD_END(sorted, current, struct class_list *);
164 /* For each object: find parent chain */
165 for (current = unsorted; schema && current; current = current->next) {
166 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
167 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
171 /* If we didn't get to the end of the list, we need to add this parent */
172 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
176 new_parent = talloc(mem_ctx, struct class_list);
177 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
178 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
184 current_lowest = NULL;
185 for (current = unsorted; schema && current; current = current->next) {
186 if(current->objectclass->subClass_order < lowest) {
187 current_lowest = current;
188 lowest = current->objectclass->subClass_order;
192 if(current_lowest != NULL) {
193 DLIST_REMOVE(unsorted,current_lowest);
194 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
200 *sorted_out = sorted;
205 /* If we don't have schema yet, then just merge the lists again */
206 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
207 *sorted_out = sorted;
211 /* This shouldn't happen, and would break MMC, perhaps there
212 * was no 'top', a conflict in the objectClasses or some other
215 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
216 return LDB_ERR_OBJECT_CLASS_VIOLATION;
219 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
221 struct ldb_context *ldb;
222 struct oc_context *ac;
225 ac = talloc_get_type(req->context, struct oc_context);
226 ldb = ldb_module_get_ctx(ac->module);
229 return ldb_module_done(ac->req, NULL, NULL,
230 LDB_ERR_OPERATIONS_ERROR);
232 if (ares->error != LDB_SUCCESS &&
233 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
234 return ldb_module_done(ac->req, ares->controls,
235 ares->response, ares->error);
238 ldb_reset_err_string(ldb);
240 switch (ares->type) {
241 case LDB_REPLY_ENTRY:
242 if (ac->search_res != NULL) {
243 ldb_set_errstring(ldb, "Too many results");
245 return ldb_module_done(ac->req, NULL, NULL,
246 LDB_ERR_OPERATIONS_ERROR);
249 ac->search_res = talloc_steal(ac, ares);
252 case LDB_REPLY_REFERRAL:
259 ret = ac->step_fn(ac);
260 if (ret != LDB_SUCCESS) {
261 return ldb_module_done(ac->req, NULL, NULL, ret);
269 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
271 struct oc_context *ac;
273 ac = talloc_get_type(req->context, struct oc_context);
276 return ldb_module_done(ac->req, NULL, NULL,
277 LDB_ERR_OPERATIONS_ERROR);
280 if (ares->type == LDB_REPLY_REFERRAL) {
281 return ldb_module_send_referral(ac->req, ares->referral);
284 if (ares->error != LDB_SUCCESS) {
285 return ldb_module_done(ac->req, ares->controls,
286 ares->response, ares->error);
289 if (ares->type != LDB_REPLY_DONE) {
291 return ldb_module_done(ac->req, NULL, NULL,
292 LDB_ERR_OPERATIONS_ERROR);
295 return ldb_module_done(ac->req, ares->controls,
296 ares->response, ares->error);
299 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
301 This should mean that if the parent is:
302 CN=Users,DC=samba,DC=example,DC=com
303 and a proposed child is
304 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
306 The resulting DN should be:
308 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
311 static int fix_dn(TALLOC_CTX *mem_ctx,
312 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
313 struct ldb_dn **fixed_dn)
315 char *upper_rdn_attr;
316 const struct ldb_val *rdn_val;
318 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
319 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
321 /* We need the attribute name in upper case */
322 upper_rdn_attr = strupper_talloc(*fixed_dn,
323 ldb_dn_get_rdn_name(newdn));
324 if (!upper_rdn_attr) {
325 return LDB_ERR_OPERATIONS_ERROR;
328 /* Create a new child */
329 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
330 return LDB_ERR_OPERATIONS_ERROR;
334 rdn_val = ldb_dn_get_rdn_val(newdn);
337 /* the rules for rDN length constraints are more complex than
338 this. Until we understand them we need to leave this
339 constraint out. Otherwise we break replication, as windows
340 does sometimes send us rDNs longer than 64 */
341 if (!rdn_val || rdn_val->length > 64) {
342 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
347 /* And replace it with CN=foo (we need the attribute in upper case */
348 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
351 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
352 static int fix_check_attributes(struct ldb_context *ldb,
353 const struct dsdb_schema *schema,
354 struct ldb_message *msg,
355 enum ldb_request_type op)
358 for (i=0; i < msg->num_elements; i++) {
359 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
360 /* Add in a very special case for 'clearTextPassword',
361 * which is used for internal processing only, and is
362 * not presented in the schema */
364 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
365 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
366 /* Apparently Windows sends exactly this behaviour */
367 return LDB_ERR_NO_SUCH_ATTRIBUTE;
370 msg->elements[i].name = attribute->lDAPDisplayName;
372 /* We have to deny write operations on constructed attributes */
373 if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
374 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
376 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
378 return LDB_ERR_CONSTRAINT_VIOLATION;
388 static int objectclass_do_add(struct oc_context *ac);
390 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
392 struct ldb_context *ldb;
393 struct ldb_request *search_req;
394 struct oc_context *ac;
395 struct ldb_dn *parent_dn;
397 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
399 ldb = ldb_module_get_ctx(module);
401 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
403 /* do not manipulate our control entries */
404 if (ldb_dn_is_special(req->op.add.message->dn)) {
405 return ldb_next_request(module, req);
408 /* the objectClass must be specified on add */
409 if (ldb_msg_find_element(req->op.add.message,
410 "objectClass") == NULL) {
411 return LDB_ERR_OBJECT_CLASS_VIOLATION;
414 ac = oc_init_context(module, req);
416 return LDB_ERR_OPERATIONS_ERROR;
419 /* If there isn't a parent, just go on to the add processing */
420 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
421 return objectclass_do_add(ac);
424 /* get copy of parent DN */
425 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
426 if (parent_dn == NULL) {
428 return LDB_ERR_OPERATIONS_ERROR;
431 ret = ldb_build_search_req(&search_req, ldb,
432 ac, parent_dn, LDB_SCOPE_BASE,
433 "(objectClass=*)", parent_attrs,
435 ac, get_search_callback,
437 if (ret != LDB_SUCCESS) {
441 ac->step_fn = objectclass_do_add;
443 return ldb_next_request(ac->module, search_req);
446 static int objectclass_do_add(struct oc_context *ac)
448 struct ldb_context *ldb;
449 const struct dsdb_schema *schema;
450 struct ldb_request *add_req;
452 struct ldb_message_element *objectclass_element, *el;
453 struct ldb_message *msg;
455 struct class_list *sorted, *current;
457 const struct dsdb_class *objectclass;
458 int32_t systemFlags = 0;
459 const char *rdn_name = NULL;
461 ldb = ldb_module_get_ctx(ac->module);
462 schema = dsdb_get_schema(ldb, ac);
464 mem_ctx = talloc_new(ac);
465 if (mem_ctx == NULL) {
467 return LDB_ERR_OPERATIONS_ERROR;
470 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
472 /* Check if we have a valid parent - this check is needed since
473 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
474 if (ac->search_res == NULL) {
475 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
476 /* Allow the tree to be started */
478 /* but don't keep any error string, it's meaningless */
479 ldb_set_errstring(ldb, NULL);
481 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
482 ldb_dn_get_linearized(msg->dn));
483 talloc_free(mem_ctx);
484 return LDB_ERR_NO_SUCH_OBJECT;
488 /* Fix up the DN to be in the standard form, taking
489 * particular care to match the parent DN */
491 ac->req->op.add.message->dn,
492 ac->search_res->message->dn,
495 if (ret != LDB_SUCCESS) {
496 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
497 ldb_dn_get_linearized(ac->req->op.add.message->dn));
498 talloc_free(mem_ctx);
504 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
505 if (ret != LDB_SUCCESS) {
506 talloc_free(mem_ctx);
510 /* This is now the objectClass list from the database */
511 objectclass_element = ldb_msg_find_element(msg, "objectClass");
513 if (!objectclass_element) {
514 /* Where did it go? bail now... */
515 talloc_free(mem_ctx);
516 return LDB_ERR_OPERATIONS_ERROR;
518 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
519 if (ret != LDB_SUCCESS) {
520 talloc_free(mem_ctx);
524 ldb_msg_remove_attr(msg, "objectClass");
525 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
527 if (ret != LDB_SUCCESS) {
528 talloc_free(mem_ctx);
532 /* We must completely replace the existing objectClass entry,
533 * because we need it sorted */
535 /* Move from the linked list back into an ldb msg */
536 for (current = sorted; current; current = current->next) {
537 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
540 talloc_free(mem_ctx);
541 return LDB_ERR_OPERATIONS_ERROR;
543 ret = ldb_msg_add_string(msg, "objectClass", value);
544 if (ret != LDB_SUCCESS) {
545 ldb_set_errstring(ldb,
546 "objectclass: could not re-add sorted "
547 "objectclass to modify msg");
548 talloc_free(mem_ctx);
553 /* Retrive the message again so get_last_structural_class works */
554 objectclass_element = ldb_msg_find_element(msg, "objectClass");
556 /* Make sure its valid to add an object of this type */
557 objectclass = get_last_structural_class(schema,objectclass_element);
558 if(objectclass == NULL) {
559 ldb_asprintf_errstring(ldb,
560 "Failed to find a structural class for %s",
561 ldb_dn_get_linearized(msg->dn));
562 return LDB_ERR_UNWILLING_TO_PERFORM;
565 rdn_name = ldb_dn_get_rdn_name(msg->dn);
566 if (objectclass->rDNAttID
567 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
568 ldb_asprintf_errstring(ldb,
569 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
570 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
571 return LDB_ERR_NAMING_VIOLATION;
574 if (ac->search_res && ac->search_res->message) {
575 struct ldb_message_element *oc_el
576 = ldb_msg_find_element(ac->search_res->message, "objectClass");
578 bool allowed_class = false;
580 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
581 const struct dsdb_class *sclass;
583 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
585 /* We don't know this class? what is going on? */
588 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
589 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
590 allowed_class = true;
596 if (!allowed_class) {
597 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
598 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
599 return LDB_ERR_NAMING_VIOLATION;
603 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
604 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
605 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
606 return LDB_ERR_UNWILLING_TO_PERFORM;
609 if (!ldb_msg_find_element(msg, "objectCategory")) {
610 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
611 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
612 /* Strip off extended components */
613 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
614 value = ldb_dn_alloc_linearized(msg, dn);
617 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
621 talloc_free(mem_ctx);
622 return LDB_ERR_OPERATIONS_ERROR;
624 ldb_msg_add_string(msg, "objectCategory", value);
626 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
627 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
631 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
632 el = ldb_msg_find_element(msg, "systemFlags");
634 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
637 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
638 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
639 ldb_msg_remove_element(msg, el);
642 /* This flag is only allowed on attributeSchema objects */
643 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
644 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
647 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
648 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
649 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
650 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
651 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
652 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
654 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
655 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
656 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
657 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
660 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
662 if (el || systemFlags != 0) {
663 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
667 talloc_free(mem_ctx);
668 ret = ldb_msg_sanity_check(ldb, msg);
671 if (ret != LDB_SUCCESS) {
675 ret = ldb_build_add_req(&add_req, ldb, ac,
680 if (ret != LDB_SUCCESS) {
684 /* perform the add */
685 return ldb_next_request(ac->module, add_req);
688 static int oc_modify_callback(struct ldb_request *req,
689 struct ldb_reply *ares);
690 static int objectclass_do_mod(struct oc_context *ac);
692 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
694 struct ldb_context *ldb = ldb_module_get_ctx(module);
695 struct ldb_message_element *objectclass_element;
696 struct ldb_message *msg;
697 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
698 struct class_list *sorted, *current;
699 struct ldb_request *down_req;
700 struct oc_context *ac;
705 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
707 /* do not manipulate our control entries */
708 if (ldb_dn_is_special(req->op.mod.message->dn)) {
709 return ldb_next_request(module, req);
712 /* Without schema, there isn't much to do here */
714 return ldb_next_request(module, req);
717 /* As with the "real" AD we don't accept empty messages */
718 if (req->op.mod.message->num_elements == 0) {
719 ldb_set_errstring(ldb, "objectclass: modify message must have "
720 "elements/attributes!");
721 return LDB_ERR_UNWILLING_TO_PERFORM;
724 ac = oc_init_context(module, req);
726 return LDB_ERR_OPERATIONS_ERROR;
729 if (!talloc_reference(ac, schema)) {
731 return LDB_ERR_OPERATIONS_ERROR;
734 /* If no part of this touches the objectClass, then we don't
735 * need to make any changes. */
736 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
738 /* If the only operation is the deletion of the objectClass
739 * then go on with just fixing the attribute case */
740 if (!objectclass_element) {
741 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
743 return LDB_ERR_OPERATIONS_ERROR;
746 ret = fix_check_attributes(ldb, schema, msg, req->operation);
747 if (ret != LDB_SUCCESS) {
751 ret = ldb_build_mod_req(&down_req, ldb, ac,
756 if (ret != LDB_SUCCESS) {
760 /* go on with the call chain */
761 return ldb_next_request(module, down_req);
764 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
765 case LDB_FLAG_MOD_DELETE:
766 if (objectclass_element->num_values == 0) {
767 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
771 case LDB_FLAG_MOD_REPLACE:
772 mem_ctx = talloc_new(ac);
773 if (mem_ctx == NULL) {
774 return LDB_ERR_OPERATIONS_ERROR;
777 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
779 talloc_free(mem_ctx);
780 return LDB_ERR_OPERATIONS_ERROR;
783 ret = fix_check_attributes(ldb, schema, msg, req->operation);
784 if (ret != LDB_SUCCESS) {
785 talloc_free(mem_ctx);
789 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
790 if (ret != LDB_SUCCESS) {
791 talloc_free(mem_ctx);
795 /* We must completely replace the existing objectClass entry,
796 * because we need it sorted */
798 ldb_msg_remove_attr(msg, "objectClass");
799 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
801 if (ret != LDB_SUCCESS) {
802 talloc_free(mem_ctx);
806 /* Move from the linked list back into an ldb msg */
807 for (current = sorted; current; current = current->next) {
808 /* copy the value as this string is on the schema
809 * context and we can't rely on it not changing
810 * before the operation is over */
811 value = talloc_strdup(msg,
812 current->objectclass->lDAPDisplayName);
815 talloc_free(mem_ctx);
816 return LDB_ERR_OPERATIONS_ERROR;
818 ret = ldb_msg_add_string(msg, "objectClass", value);
819 if (ret != LDB_SUCCESS) {
820 ldb_set_errstring(ldb,
821 "objectclass: could not re-add sorted "
822 "objectclass to modify msg");
823 talloc_free(mem_ctx);
828 talloc_free(mem_ctx);
830 ret = ldb_msg_sanity_check(ldb, msg);
831 if (ret != LDB_SUCCESS) {
835 ret = ldb_build_mod_req(&down_req, ldb, ac,
840 if (ret != LDB_SUCCESS) {
844 /* go on with the call chain */
845 return ldb_next_request(module, down_req);
848 /* This isn't the default branch of the switch, but a 'in any
849 * other case'. When a delete isn't for all objectClasses for
853 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
856 return LDB_ERR_OPERATIONS_ERROR;
859 ret = fix_check_attributes(ldb, schema, msg, req->operation);
860 if (ret != LDB_SUCCESS) {
865 ret = ldb_build_mod_req(&down_req, ldb, ac,
868 ac, oc_modify_callback,
870 if (ret != LDB_SUCCESS) {
874 return ldb_next_request(module, down_req);
877 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
879 struct ldb_context *ldb;
880 static const char * const attrs[] = { "objectClass", NULL };
881 struct ldb_request *search_req;
882 struct oc_context *ac;
885 ac = talloc_get_type(req->context, struct oc_context);
886 ldb = ldb_module_get_ctx(ac->module);
889 return ldb_module_done(ac->req, NULL, NULL,
890 LDB_ERR_OPERATIONS_ERROR);
893 if (ares->type == LDB_REPLY_REFERRAL) {
894 return ldb_module_send_referral(ac->req, ares->referral);
897 if (ares->error != LDB_SUCCESS) {
898 return ldb_module_done(ac->req, ares->controls,
899 ares->response, ares->error);
902 if (ares->type != LDB_REPLY_DONE) {
904 return ldb_module_done(ac->req, NULL, NULL,
905 LDB_ERR_OPERATIONS_ERROR);
910 ret = ldb_build_search_req(&search_req, ldb, ac,
911 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
914 ac, get_search_callback,
916 if (ret != LDB_SUCCESS) {
917 return ldb_module_done(ac->req, NULL, NULL, ret);
920 ac->step_fn = objectclass_do_mod;
922 ret = ldb_next_request(ac->module, search_req);
923 if (ret != LDB_SUCCESS) {
924 return ldb_module_done(ac->req, NULL, NULL, ret);
929 static int objectclass_do_mod(struct oc_context *ac)
931 struct ldb_context *ldb;
932 const struct dsdb_schema *schema;
933 struct ldb_request *mod_req;
935 struct ldb_message_element *objectclass_element;
936 struct ldb_message *msg;
938 struct class_list *sorted, *current;
941 ldb = ldb_module_get_ctx(ac->module);
943 if (ac->search_res == NULL) {
944 return LDB_ERR_OPERATIONS_ERROR;
946 schema = dsdb_get_schema(ldb, ac);
948 mem_ctx = talloc_new(ac);
949 if (mem_ctx == NULL) {
950 return LDB_ERR_OPERATIONS_ERROR;
953 /* use a new message structure */
954 msg = ldb_msg_new(ac);
956 ldb_set_errstring(ldb,
957 "objectclass: could not create new modify msg");
958 talloc_free(mem_ctx);
959 return LDB_ERR_OPERATIONS_ERROR;
962 /* This is now the objectClass list from the database */
963 objectclass_element = ldb_msg_find_element(ac->search_res->message,
965 if (!objectclass_element) {
966 /* Where did it go? bail now... */
967 talloc_free(mem_ctx);
968 return LDB_ERR_OPERATIONS_ERROR;
972 msg->dn = ac->req->op.mod.message->dn;
974 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
975 if (ret != LDB_SUCCESS) {
979 /* We must completely replace the existing objectClass entry.
980 * We could do a constrained add/del, but we are meant to be
981 * in a transaction... */
983 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
984 if (ret != LDB_SUCCESS) {
985 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
986 talloc_free(mem_ctx);
990 /* Move from the linked list back into an ldb msg */
991 for (current = sorted; current; current = current->next) {
992 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
995 return LDB_ERR_OPERATIONS_ERROR;
997 ret = ldb_msg_add_string(msg, "objectClass", value);
998 if (ret != LDB_SUCCESS) {
999 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1000 talloc_free(mem_ctx);
1005 ret = ldb_msg_sanity_check(ldb, msg);
1006 if (ret != LDB_SUCCESS) {
1007 talloc_free(mem_ctx);
1011 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1016 if (ret != LDB_SUCCESS) {
1017 talloc_free(mem_ctx);
1021 talloc_free(mem_ctx);
1022 /* perform the modify */
1023 return ldb_next_request(ac->module, mod_req);
1026 static int objectclass_do_rename(struct oc_context *ac);
1028 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1030 static const char * const attrs[] = { NULL };
1031 struct ldb_context *ldb;
1032 struct ldb_request *search_req;
1033 struct oc_context *ac;
1034 struct ldb_dn *parent_dn;
1037 ldb = ldb_module_get_ctx(module);
1039 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1041 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1042 return ldb_next_request(module, req);
1045 /* Firstly ensure we are not trying to rename it to be a child of itself */
1046 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1047 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1048 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1049 ldb_dn_get_linearized(req->op.rename.olddn));
1050 return LDB_ERR_UNWILLING_TO_PERFORM;
1053 ac = oc_init_context(module, req);
1055 return LDB_ERR_OPERATIONS_ERROR;
1058 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1059 if (parent_dn == NULL) {
1061 return LDB_ERR_OPERATIONS_ERROR;
1065 it makes a search request, looking for the parent DN to fix up the new DN
1066 to a standard one, at objectclass_do_rename()
1068 ret = ldb_build_search_req(&search_req, ldb,
1069 ac, parent_dn, LDB_SCOPE_BASE,
1072 ac, get_search_callback,
1074 if (ret != LDB_SUCCESS) {
1078 /* we have to add the show deleted control, as otherwise DRS
1079 deletes will be refused as we will think the target parent
1081 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1083 if (ret != LDB_SUCCESS) {
1087 ac->step_fn = objectclass_do_rename;
1089 return ldb_next_request(ac->module, search_req);
1094 static int objectclass_do_rename(struct oc_context *ac)
1096 struct ldb_context *ldb;
1097 struct ldb_request *rename_req;
1098 struct ldb_dn *fixed_dn;
1101 ldb = ldb_module_get_ctx(ac->module);
1103 /* Check we have a valid parent */
1104 if (ac->search_res == NULL) {
1105 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1106 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1107 return LDB_ERR_UNWILLING_TO_PERFORM;
1110 /* Fix up the DN to be in the standard form,
1111 * taking particular care to match the parent DN */
1113 ac->req->op.rename.newdn,
1114 ac->search_res->message->dn,
1116 if (ret != LDB_SUCCESS) {
1120 /* TODO: Check this is a valid child to this parent,
1121 * by reading the allowedChildClasses and
1122 * allowedChildClasssesEffective attributes */
1124 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1125 ac->req->op.rename.olddn, fixed_dn,
1129 if (ret != LDB_SUCCESS) {
1133 /* perform the rename */
1134 return ldb_next_request(ac->module, rename_req);
1137 static int objectclass_init(struct ldb_module *module)
1139 struct ldb_context *ldb = ldb_module_get_ctx(module);
1141 /* Init everything else */
1142 ret = ldb_next_init(module);
1143 if (ret != LDB_SUCCESS) {
1147 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1148 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1153 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1154 .name = "objectclass",
1155 .add = objectclass_add,
1156 .modify = objectclass_modify,
1157 .rename = objectclass_rename,
1158 .init_context = objectclass_init