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"
49 struct ldb_module *module;
50 struct ldb_request *req;
52 struct ldb_reply *search_res;
54 int (*step_fn)(struct oc_context *);
58 struct class_list *prev, *next;
59 const struct dsdb_class *objectclass;
62 static struct oc_context *oc_init_context(struct ldb_module *module,
63 struct ldb_request *req)
65 struct ldb_context *ldb;
66 struct oc_context *ac;
68 ldb = ldb_module_get_ctx(module);
70 ac = talloc_zero(req, struct oc_context);
72 ldb_set_errstring(ldb, "Out of Memory");
82 static int objectclass_do_add(struct oc_context *ac);
84 /* Sort objectClasses into correct order, and validate that all
85 * objectClasses specified actually exist in the schema
88 static int objectclass_sort(struct ldb_module *module,
89 const struct dsdb_schema *schema,
91 struct ldb_message_element *objectclass_element,
92 struct class_list **sorted_out)
94 struct ldb_context *ldb;
97 struct class_list *sorted = NULL, *parent_class = NULL,
98 *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent;
100 ldb = ldb_module_get_ctx(module);
104 * We work on 4 different 'bins' (implemented here as linked lists):
106 * * sorted: the eventual list, in the order we wish to push
107 * into the database. This is the only ordered list.
109 * * parent_class: The current parent class 'bin' we are
110 * trying to find subclasses for
112 * * subclass: The subclasses we have found so far
114 * * unsorted: The remaining objectClasses
116 * The process is a matter of filtering objectClasses up from
117 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
119 * We start with 'top' (found and promoted to parent_class
120 * initially). Then we find (in unsorted) all the direct
121 * subclasses of 'top'. parent_classes is concatenated onto
122 * the end of 'sorted', and subclass becomes the list in
125 * We then repeat, until we find no more subclasses. Any left
126 * over classes are added to the end.
130 /* Firstly, dump all the objectClass elements into the
131 * unsorted bin, except for 'top', which is special */
132 for (i=0; i < objectclass_element->num_values; i++) {
133 current = talloc(mem_ctx, struct class_list);
136 return LDB_ERR_OPERATIONS_ERROR;
138 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
139 if (!current->objectclass) {
140 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
141 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
142 /* This looks weird, but windows apparently returns this for invalid objectClass values */
143 return LDB_ERR_NO_SUCH_ATTRIBUTE;
144 } else if (current->objectclass->isDefunct) {
145 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
146 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
147 /* This looks weird, but windows apparently returns this for invalid objectClass values */
148 return LDB_ERR_NO_SUCH_ATTRIBUTE;
151 /* this is the root of the tree. We will start
152 * looking for subclasses from here */
153 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) {
154 DLIST_ADD_END(parent_class, current, struct class_list *);
156 DLIST_ADD_END(unsorted, current, struct class_list *);
160 if (parent_class == NULL) {
161 current = talloc(mem_ctx, struct class_list);
162 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
163 DLIST_ADD_END(parent_class, current, struct class_list *);
166 /* For each object: find parent chain */
167 for (current = unsorted; schema && current; current = current->next) {
168 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
169 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
173 /* If we didn't get to the end of the list, we need to add this parent */
174 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
178 new_parent = talloc(mem_ctx, struct class_list);
179 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
180 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
183 /* DEBUGGING aid: how many layers are we down now? */
187 /* Find all the subclasses of classes in the
188 * parent_classes. Push them onto the subclass list */
190 /* Ensure we don't bother if there are no unsorted entries left */
191 for (current = parent_class; schema && unsorted && current; current = current->next) {
192 /* Walk the list of possible subclasses in unsorted */
193 for (poss_subclass = unsorted; poss_subclass; ) {
194 struct class_list *next;
196 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
197 next = poss_subclass->next;
199 if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) {
200 DLIST_REMOVE(unsorted, poss_subclass);
201 DLIST_ADD(subclass, poss_subclass);
205 poss_subclass = next;
209 /* Now push the parent_classes as sorted, we are done with
210 these. Add to the END of the list by concatenation */
211 DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
213 /* and now find subclasses of these */
214 parent_class = subclass;
217 /* If we didn't find any subclasses we will fall out
219 } while (parent_class);
222 *sorted_out = sorted;
227 /* If we don't have schema yet, then just merge the lists again */
228 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
229 *sorted_out = sorted;
233 /* This shouldn't happen, and would break MMC, perhaps there
234 * was no 'top', a conflict in the objectClasses or some other
237 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
238 return LDB_ERR_OBJECT_CLASS_VIOLATION;
241 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
243 struct ldb_context *ldb;
244 struct oc_context *ac;
247 ac = talloc_get_type(req->context, struct oc_context);
248 ldb = ldb_module_get_ctx(ac->module);
251 return ldb_module_done(ac->req, NULL, NULL,
252 LDB_ERR_OPERATIONS_ERROR);
254 if (ares->error != LDB_SUCCESS &&
255 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
256 return ldb_module_done(ac->req, ares->controls,
257 ares->response, ares->error);
260 ldb_reset_err_string(ldb);
262 switch (ares->type) {
263 case LDB_REPLY_ENTRY:
264 if (ac->search_res != NULL) {
265 ldb_set_errstring(ldb, "Too many results");
267 return ldb_module_done(ac->req, NULL, NULL,
268 LDB_ERR_OPERATIONS_ERROR);
271 ac->search_res = talloc_steal(ac, ares);
274 case LDB_REPLY_REFERRAL:
281 ret = ac->step_fn(ac);
282 if (ret != LDB_SUCCESS) {
283 return ldb_module_done(ac->req, NULL, NULL, ret);
291 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
293 struct oc_context *ac;
295 ac = talloc_get_type(req->context, struct oc_context);
298 return ldb_module_done(ac->req, NULL, NULL,
299 LDB_ERR_OPERATIONS_ERROR);
301 if (ares->error != LDB_SUCCESS) {
302 return ldb_module_done(ac->req, ares->controls,
303 ares->response, ares->error);
306 if (ares->type != LDB_REPLY_DONE) {
308 return ldb_module_done(ac->req, NULL, NULL,
309 LDB_ERR_OPERATIONS_ERROR);
312 return ldb_module_done(ac->req, ares->controls,
313 ares->response, ares->error);
316 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
318 This should mean that if the parent is:
319 CN=Users,DC=samba,DC=example,DC=com
320 and a proposed child is
321 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
323 The resulting DN should be:
325 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
328 static int fix_dn(TALLOC_CTX *mem_ctx,
329 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
330 struct ldb_dn **fixed_dn)
332 char *upper_rdn_attr;
333 const struct ldb_val *rdn_val;
335 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
336 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
338 /* We need the attribute name in upper case */
339 upper_rdn_attr = strupper_talloc(*fixed_dn,
340 ldb_dn_get_rdn_name(newdn));
341 if (!upper_rdn_attr) {
342 return LDB_ERR_OPERATIONS_ERROR;
345 /* Create a new child */
346 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
347 return LDB_ERR_OPERATIONS_ERROR;
351 rdn_val = ldb_dn_get_rdn_val(newdn);
354 /* the rules for rDN length constraints are more complex than
355 this. Until we understand them we need to leave this
356 constraint out. Otherwise we break replication, as windows
357 does sometimes send us rDNs longer than 64 */
358 if (!rdn_val || rdn_val->length > 64) {
359 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
364 /* And replace it with CN=foo (we need the attribute in upper case */
365 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
368 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
369 static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg)
372 for (i=0; i < msg->num_elements; i++) {
373 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
374 /* Add in a very special case for 'clearTextPassword',
375 * which is used for internal processing only, and is
376 * not presented in the schema */
378 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
379 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
380 /* Apparently Windows sends exactly this behaviour */
381 return LDB_ERR_NO_SUCH_ATTRIBUTE;
384 msg->elements[i].name = attribute->lDAPDisplayName;
391 static int objectclass_do_add(struct oc_context *ac);
393 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
395 struct ldb_context *ldb;
396 struct ldb_request *search_req;
397 struct oc_context *ac;
398 struct ldb_dn *parent_dn;
400 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
402 ldb = ldb_module_get_ctx(module);
404 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
406 /* do not manipulate our control entries */
407 if (ldb_dn_is_special(req->op.add.message->dn)) {
408 return ldb_next_request(module, req);
411 /* the objectClass must be specified on add */
412 if (ldb_msg_find_element(req->op.add.message,
413 "objectClass") == NULL) {
414 return LDB_ERR_OBJECT_CLASS_VIOLATION;
417 ac = oc_init_context(module, req);
419 return LDB_ERR_OPERATIONS_ERROR;
422 /* If there isn't a parent, just go on to the add processing */
423 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
424 return objectclass_do_add(ac);
427 /* get copy of parent DN */
428 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
429 if (parent_dn == NULL) {
431 return LDB_ERR_OPERATIONS_ERROR;
434 ret = ldb_build_search_req(&search_req, ldb,
435 ac, parent_dn, LDB_SCOPE_BASE,
436 "(objectClass=*)", parent_attrs,
438 ac, get_search_callback,
440 if (ret != LDB_SUCCESS) {
443 talloc_steal(search_req, parent_dn);
445 ac->step_fn = objectclass_do_add;
447 return ldb_next_request(ac->module, search_req);
450 static int objectclass_do_add(struct oc_context *ac)
452 struct ldb_context *ldb;
453 const struct dsdb_schema *schema;
454 struct ldb_request *add_req;
456 struct ldb_message_element *objectclass_element;
457 struct ldb_message *msg;
459 struct class_list *sorted, *current;
462 ldb = ldb_module_get_ctx(ac->module);
463 schema = dsdb_get_schema(ldb);
465 mem_ctx = talloc_new(ac);
466 if (mem_ctx == NULL) {
467 return LDB_ERR_OPERATIONS_ERROR;
470 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
472 /* Check we have a valid parent */
473 if (ac->search_res == NULL) {
474 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
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 particular care to match the parent DN */
490 ac->req->op.add.message->dn,
491 ac->search_res->message->dn,
494 if (ret != LDB_SUCCESS) {
495 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
496 ldb_dn_get_linearized(ac->req->op.add.message->dn));
497 talloc_free(mem_ctx);
503 ret = fix_attributes(ldb, schema, msg);
504 if (ret != LDB_SUCCESS) {
505 talloc_free(mem_ctx);
509 /* This is now the objectClass list from the database */
510 objectclass_element = ldb_msg_find_element(msg, "objectClass");
512 if (!objectclass_element) {
513 /* Where did it go? bail now... */
514 talloc_free(mem_ctx);
515 return LDB_ERR_OPERATIONS_ERROR;
517 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
518 if (ret != LDB_SUCCESS) {
519 talloc_free(mem_ctx);
523 ldb_msg_remove_attr(msg, "objectClass");
524 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
526 if (ret != LDB_SUCCESS) {
527 talloc_free(mem_ctx);
531 /* We must completely replace the existing objectClass entry,
532 * because we need it sorted */
534 /* Move from the linked list back into an ldb msg */
535 for (current = sorted; current; current = current->next) {
536 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
539 talloc_free(mem_ctx);
540 return LDB_ERR_OPERATIONS_ERROR;
542 ret = ldb_msg_add_string(msg, "objectClass", value);
543 if (ret != LDB_SUCCESS) {
544 ldb_set_errstring(ldb,
545 "objectclass: could not re-add sorted "
546 "objectclass to modify msg");
547 talloc_free(mem_ctx);
550 /* Last one is the critical one */
551 if (!current->next) {
552 struct ldb_message_element *el;
553 int32_t systemFlags = 0;
554 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
555 if (current->objectclass->rDNAttID
556 && ldb_attr_cmp(rdn_name, current->objectclass->rDNAttID) != 0) {
557 ldb_asprintf_errstring(ldb,
558 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
559 rdn_name, current->objectclass->lDAPDisplayName, current->objectclass->rDNAttID);
560 return LDB_ERR_NAMING_VIOLATION;
563 if (ac->search_res && ac->search_res->message) {
564 struct ldb_message_element *oc_el
565 = ldb_msg_find_element(ac->search_res->message, "objectClass");
567 bool allowed_class = false;
569 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
570 const struct dsdb_class *sclass;
572 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
574 /* We don't know this class? what is going on? */
577 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
578 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
579 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
580 allowed_class = true;
585 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
586 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
587 allowed_class = true;
594 if (!allowed_class) {
595 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
596 current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
597 return LDB_ERR_NAMING_VIOLATION;
601 if (current->objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
602 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
603 current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
604 return LDB_ERR_UNWILLING_TO_PERFORM;
607 if (!ldb_msg_find_element(msg, "objectCategory")) {
608 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
609 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
610 /* Strip off extended components */
611 struct ldb_dn *dn = ldb_dn_new(msg, ldb, current->objectclass->defaultObjectCategory);
612 value = ldb_dn_alloc_linearized(msg, dn);
615 value = talloc_strdup(msg, current->objectclass->defaultObjectCategory);
619 talloc_free(mem_ctx);
620 return LDB_ERR_OPERATIONS_ERROR;
622 ldb_msg_add_string(msg, "objectCategory", value);
624 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
625 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
629 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
630 el = ldb_msg_find_element(msg, "systemFlags");
632 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
635 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
636 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
637 ldb_msg_remove_element(msg, el);
640 /* This flag is only allowed on attributeSchema objects */
641 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) {
642 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
645 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "server") == 0) {
646 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
647 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "site") == 0
648 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "serverContainer") == 0
649 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
650 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
652 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0
653 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0
654 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
655 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
658 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
660 if (el || systemFlags != 0) {
661 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);
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 no part of this touches the objectClass, then we don't
730 * need to make any changes. */
731 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
733 /* If the only operation is the deletion of the objectClass
734 * then go on with just fixing the attribute case */
735 if (!objectclass_element) {
736 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
738 return LDB_ERR_OPERATIONS_ERROR;
741 ret = fix_attributes(ldb, schema, msg);
742 if (ret != LDB_SUCCESS) {
746 ret = ldb_build_mod_req(&down_req, ldb, ac,
751 if (ret != LDB_SUCCESS) {
755 /* go on with the call chain */
756 return ldb_next_request(module, down_req);
759 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
760 case LDB_FLAG_MOD_DELETE:
761 if (objectclass_element->num_values == 0) {
762 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
766 case LDB_FLAG_MOD_REPLACE:
767 mem_ctx = talloc_new(ac);
768 if (mem_ctx == NULL) {
769 return LDB_ERR_OPERATIONS_ERROR;
772 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
774 talloc_free(mem_ctx);
775 return LDB_ERR_OPERATIONS_ERROR;
778 ret = fix_attributes(ldb, schema, msg);
779 if (ret != LDB_SUCCESS) {
780 talloc_free(mem_ctx);
784 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
785 if (ret != LDB_SUCCESS) {
786 talloc_free(mem_ctx);
790 /* We must completely replace the existing objectClass entry,
791 * because we need it sorted */
793 ldb_msg_remove_attr(msg, "objectClass");
794 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
796 if (ret != LDB_SUCCESS) {
797 talloc_free(mem_ctx);
801 /* Move from the linked list back into an ldb msg */
802 for (current = sorted; current; current = current->next) {
803 /* copy the value as this string is on the schema
804 * context and we can't rely on it not changing
805 * before the operation is over */
806 value = talloc_strdup(msg,
807 current->objectclass->lDAPDisplayName);
810 talloc_free(mem_ctx);
811 return LDB_ERR_OPERATIONS_ERROR;
813 ret = ldb_msg_add_string(msg, "objectClass", value);
814 if (ret != LDB_SUCCESS) {
815 ldb_set_errstring(ldb,
816 "objectclass: could not re-add sorted "
817 "objectclass to modify msg");
818 talloc_free(mem_ctx);
823 talloc_free(mem_ctx);
825 ret = ldb_msg_sanity_check(ldb, msg);
826 if (ret != LDB_SUCCESS) {
830 ret = ldb_build_mod_req(&down_req, ldb, ac,
835 if (ret != LDB_SUCCESS) {
839 /* go on with the call chain */
840 return ldb_next_request(module, down_req);
843 /* This isn't the default branch of the switch, but a 'in any
844 * other case'. When a delete isn't for all objectClasses for
848 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
851 return LDB_ERR_OPERATIONS_ERROR;
854 ret = fix_attributes(ldb, schema, msg);
855 if (ret != LDB_SUCCESS) {
860 ret = ldb_build_mod_req(&down_req, ldb, ac,
863 ac, oc_modify_callback,
865 if (ret != LDB_SUCCESS) {
869 return ldb_next_request(module, down_req);
872 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
874 struct ldb_context *ldb;
875 static const char * const attrs[] = { "objectClass", NULL };
876 struct ldb_request *search_req;
877 struct oc_context *ac;
880 ac = talloc_get_type(req->context, struct oc_context);
881 ldb = ldb_module_get_ctx(ac->module);
884 return ldb_module_done(ac->req, NULL, NULL,
885 LDB_ERR_OPERATIONS_ERROR);
887 if (ares->error != LDB_SUCCESS) {
888 return ldb_module_done(ac->req, ares->controls,
889 ares->response, ares->error);
892 if (ares->type != LDB_REPLY_DONE) {
894 return ldb_module_done(ac->req, NULL, NULL,
895 LDB_ERR_OPERATIONS_ERROR);
900 ret = ldb_build_search_req(&search_req, ldb, ac,
901 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
904 ac, get_search_callback,
906 if (ret != LDB_SUCCESS) {
907 return ldb_module_done(ac->req, NULL, NULL, ret);
910 ac->step_fn = objectclass_do_mod;
912 ret = ldb_next_request(ac->module, search_req);
913 if (ret != LDB_SUCCESS) {
914 return ldb_module_done(ac->req, NULL, NULL, ret);
919 static int objectclass_do_mod(struct oc_context *ac)
921 struct ldb_context *ldb;
922 const struct dsdb_schema *schema;
923 struct ldb_request *mod_req;
925 struct ldb_message_element *objectclass_element;
926 struct ldb_message *msg;
928 struct class_list *sorted, *current;
931 ldb = ldb_module_get_ctx(ac->module);
933 if (ac->search_res == NULL) {
934 return LDB_ERR_OPERATIONS_ERROR;
936 schema = dsdb_get_schema(ldb);
938 mem_ctx = talloc_new(ac);
939 if (mem_ctx == NULL) {
940 return LDB_ERR_OPERATIONS_ERROR;
943 /* use a new message structure */
944 msg = ldb_msg_new(ac);
946 ldb_set_errstring(ldb,
947 "objectclass: could not create new modify msg");
948 talloc_free(mem_ctx);
949 return LDB_ERR_OPERATIONS_ERROR;
952 /* This is now the objectClass list from the database */
953 objectclass_element = ldb_msg_find_element(ac->search_res->message,
955 if (!objectclass_element) {
956 /* Where did it go? bail now... */
957 talloc_free(mem_ctx);
958 return LDB_ERR_OPERATIONS_ERROR;
962 msg->dn = ac->req->op.mod.message->dn;
964 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
965 if (ret != LDB_SUCCESS) {
969 /* We must completely replace the existing objectClass entry.
970 * We could do a constrained add/del, but we are meant to be
971 * in a transaction... */
973 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
974 if (ret != LDB_SUCCESS) {
975 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
976 talloc_free(mem_ctx);
980 /* Move from the linked list back into an ldb msg */
981 for (current = sorted; current; current = current->next) {
982 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
985 return LDB_ERR_OPERATIONS_ERROR;
987 ret = ldb_msg_add_string(msg, "objectClass", value);
988 if (ret != LDB_SUCCESS) {
989 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
990 talloc_free(mem_ctx);
995 ret = ldb_msg_sanity_check(ldb, msg);
996 if (ret != LDB_SUCCESS) {
997 talloc_free(mem_ctx);
1001 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1006 if (ret != LDB_SUCCESS) {
1007 talloc_free(mem_ctx);
1011 talloc_free(mem_ctx);
1012 /* perform the modify */
1013 return ldb_next_request(ac->module, mod_req);
1016 static int objectclass_do_rename(struct oc_context *ac);
1018 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1020 static const char * const attrs[] = { NULL };
1021 struct ldb_context *ldb;
1022 struct ldb_request *search_req;
1023 struct oc_context *ac;
1024 struct ldb_dn *parent_dn;
1027 ldb = ldb_module_get_ctx(module);
1029 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1031 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1032 return ldb_next_request(module, req);
1035 /* Firstly ensure we are not trying to rename it to be a child of itself */
1036 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1037 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1038 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1039 ldb_dn_get_linearized(req->op.rename.olddn));
1040 return LDB_ERR_UNWILLING_TO_PERFORM;
1043 ac = oc_init_context(module, req);
1045 return LDB_ERR_OPERATIONS_ERROR;
1048 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1049 if (parent_dn == NULL) {
1051 return LDB_ERR_OPERATIONS_ERROR;
1055 it makes a search request, looking for the parent DN to fix up the new DN
1056 to a standard one, at objectclass_do_rename()
1058 ret = ldb_build_search_req(&search_req, ldb,
1059 ac, parent_dn, LDB_SCOPE_BASE,
1062 ac, get_search_callback,
1064 if (ret != LDB_SUCCESS) {
1068 /* we have to add the show deleted control, as otherwise DRS
1069 deletes will be refused as we will think the target parent
1071 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1073 if (ret != LDB_SUCCESS) {
1077 ac->step_fn = objectclass_do_rename;
1079 return ldb_next_request(ac->module, search_req);
1084 static int objectclass_do_rename(struct oc_context *ac)
1086 struct ldb_context *ldb;
1087 struct ldb_request *rename_req;
1088 struct ldb_dn *fixed_dn;
1091 ldb = ldb_module_get_ctx(ac->module);
1093 /* Check we have a valid parent */
1094 if (ac->search_res == NULL) {
1095 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1096 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1097 return LDB_ERR_UNWILLING_TO_PERFORM;
1100 /* Fix up the DN to be in the standard form,
1101 * taking particular care to match the parent DN */
1103 ac->req->op.rename.newdn,
1104 ac->search_res->message->dn,
1106 if (ret != LDB_SUCCESS) {
1110 /* TODO: Check this is a valid child to this parent,
1111 * by reading the allowedChildClasses and
1112 * allowedChildClasssesEffective attributes */
1114 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1115 ac->req->op.rename.olddn, fixed_dn,
1119 if (ret != LDB_SUCCESS) {
1123 /* perform the rename */
1124 return ldb_next_request(ac->module, rename_req);
1127 static int objectclass_init(struct ldb_module *module)
1129 struct ldb_context *ldb = ldb_module_get_ctx(module);
1131 /* Init everything else */
1132 ret = ldb_next_init(module);
1133 if (ret != LDB_SUCCESS) {
1137 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1138 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1140 return ldb_next_init(module);
1143 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1144 .name = "objectclass",
1145 .add = objectclass_add,
1146 .modify = objectclass_modify,
1147 .rename = objectclass_rename,
1148 .init_context = objectclass_init