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);
278 if (ares->type == LDB_REPLY_REFERRAL) {
279 return ldb_module_send_referral(ac->req, ares->referral);
282 if (ares->error != LDB_SUCCESS) {
283 return ldb_module_done(ac->req, ares->controls,
284 ares->response, ares->error);
287 if (ares->type != LDB_REPLY_DONE) {
289 return ldb_module_done(ac->req, NULL, NULL,
290 LDB_ERR_OPERATIONS_ERROR);
293 return ldb_module_done(ac->req, ares->controls,
294 ares->response, ares->error);
297 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
299 This should mean that if the parent is:
300 CN=Users,DC=samba,DC=example,DC=com
301 and a proposed child is
302 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
304 The resulting DN should be:
306 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
309 static int fix_dn(TALLOC_CTX *mem_ctx,
310 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
311 struct ldb_dn **fixed_dn)
313 char *upper_rdn_attr;
314 const struct ldb_val *rdn_val;
316 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
317 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
319 /* We need the attribute name in upper case */
320 upper_rdn_attr = strupper_talloc(*fixed_dn,
321 ldb_dn_get_rdn_name(newdn));
322 if (!upper_rdn_attr) {
323 return LDB_ERR_OPERATIONS_ERROR;
326 /* Create a new child */
327 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
328 return LDB_ERR_OPERATIONS_ERROR;
332 rdn_val = ldb_dn_get_rdn_val(newdn);
335 /* the rules for rDN length constraints are more complex than
336 this. Until we understand them we need to leave this
337 constraint out. Otherwise we break replication, as windows
338 does sometimes send us rDNs longer than 64 */
339 if (!rdn_val || rdn_val->length > 64) {
340 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
345 /* And replace it with CN=foo (we need the attribute in upper case */
346 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
349 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
350 static int fix_check_attributes(struct ldb_context *ldb,
351 const struct dsdb_schema *schema,
352 struct ldb_message *msg,
353 enum ldb_request_type op)
356 for (i=0; i < msg->num_elements; i++) {
357 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
358 /* Add in a very special case for 'clearTextPassword',
359 * which is used for internal processing only, and is
360 * not presented in the schema */
362 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
363 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
364 /* Apparently Windows sends exactly this behaviour */
365 return LDB_ERR_NO_SUCH_ATTRIBUTE;
368 msg->elements[i].name = attribute->lDAPDisplayName;
370 /* We have to deny write operations on constructed attributes */
371 if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
372 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
374 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
376 return LDB_ERR_CONSTRAINT_VIOLATION;
386 static int objectclass_do_add(struct oc_context *ac);
388 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
390 struct ldb_context *ldb;
391 struct ldb_request *search_req;
392 struct oc_context *ac;
393 struct ldb_dn *parent_dn;
395 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
397 ldb = ldb_module_get_ctx(module);
399 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
401 /* do not manipulate our control entries */
402 if (ldb_dn_is_special(req->op.add.message->dn)) {
403 return ldb_next_request(module, req);
406 /* the objectClass must be specified on add */
407 if (ldb_msg_find_element(req->op.add.message,
408 "objectClass") == NULL) {
409 return LDB_ERR_OBJECT_CLASS_VIOLATION;
412 ac = oc_init_context(module, req);
414 return LDB_ERR_OPERATIONS_ERROR;
417 /* If there isn't a parent, just go on to the add processing */
418 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
419 return objectclass_do_add(ac);
422 /* get copy of parent DN */
423 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
424 if (parent_dn == NULL) {
426 return LDB_ERR_OPERATIONS_ERROR;
429 ret = ldb_build_search_req(&search_req, ldb,
430 ac, parent_dn, LDB_SCOPE_BASE,
431 "(objectClass=*)", parent_attrs,
433 ac, get_search_callback,
435 if (ret != LDB_SUCCESS) {
438 talloc_steal(search_req, parent_dn);
440 ac->step_fn = objectclass_do_add;
442 return ldb_next_request(ac->module, search_req);
445 static int objectclass_do_add(struct oc_context *ac)
447 struct ldb_context *ldb;
448 const struct dsdb_schema *schema;
449 struct ldb_request *add_req;
451 struct ldb_message_element *objectclass_element, *el;
452 struct ldb_message *msg;
454 struct class_list *sorted, *current;
456 const struct dsdb_class *objectclass;
457 int32_t systemFlags = 0;
458 const char *rdn_name = NULL;
460 ldb = ldb_module_get_ctx(ac->module);
461 schema = dsdb_get_schema(ldb, ac);
463 mem_ctx = talloc_new(ac);
464 if (mem_ctx == NULL) {
466 return LDB_ERR_OPERATIONS_ERROR;
469 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
471 /* Check we have a valid parent */
472 if (ac->search_res == NULL) {
473 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
474 /* Allow the tree to be started */
476 /* but don't keep any error string, it's meaningless */
477 ldb_set_errstring(ldb, NULL);
479 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
480 ldb_dn_get_linearized(msg->dn));
481 talloc_free(mem_ctx);
482 return LDB_ERR_NO_SUCH_OBJECT;
486 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
488 ac->req->op.add.message->dn,
489 ac->search_res->message->dn,
492 if (ret != LDB_SUCCESS) {
493 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
494 ldb_dn_get_linearized(ac->req->op.add.message->dn));
495 talloc_free(mem_ctx);
501 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
502 if (ret != LDB_SUCCESS) {
503 talloc_free(mem_ctx);
507 /* This is now the objectClass list from the database */
508 objectclass_element = ldb_msg_find_element(msg, "objectClass");
510 if (!objectclass_element) {
511 /* Where did it go? bail now... */
512 talloc_free(mem_ctx);
513 return LDB_ERR_OPERATIONS_ERROR;
515 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
516 if (ret != LDB_SUCCESS) {
517 talloc_free(mem_ctx);
521 ldb_msg_remove_attr(msg, "objectClass");
522 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
524 if (ret != LDB_SUCCESS) {
525 talloc_free(mem_ctx);
529 /* We must completely replace the existing objectClass entry,
530 * because we need it sorted */
532 /* Move from the linked list back into an ldb msg */
533 for (current = sorted; current; current = current->next) {
534 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
537 talloc_free(mem_ctx);
538 return LDB_ERR_OPERATIONS_ERROR;
540 ret = ldb_msg_add_string(msg, "objectClass", value);
541 if (ret != LDB_SUCCESS) {
542 ldb_set_errstring(ldb,
543 "objectclass: could not re-add sorted "
544 "objectclass to modify msg");
545 talloc_free(mem_ctx);
550 /* Retrive the message again so get_last_structural_class works */
551 objectclass_element = ldb_msg_find_element(msg, "objectClass");
553 /* Make sure its valid to add an object of this type */
554 objectclass = get_last_structural_class(schema,objectclass_element);
555 if(objectclass == NULL) {
556 ldb_asprintf_errstring(ldb,
557 "Failed to find a structural class for %s",
558 ldb_dn_get_linearized(msg->dn));
559 return LDB_ERR_NAMING_VIOLATION;
562 rdn_name = ldb_dn_get_rdn_name(msg->dn);
563 if (objectclass->rDNAttID
564 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
565 ldb_asprintf_errstring(ldb,
566 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
567 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
568 return LDB_ERR_NAMING_VIOLATION;
571 if (ac->search_res && ac->search_res->message) {
572 struct ldb_message_element *oc_el
573 = ldb_msg_find_element(ac->search_res->message, "objectClass");
575 bool allowed_class = false;
577 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
578 const struct dsdb_class *sclass;
580 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
582 /* We don't know this class? what is going on? */
585 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
586 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
587 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
588 allowed_class = true;
593 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
594 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
595 allowed_class = true;
602 if (!allowed_class) {
603 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
604 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
605 return LDB_ERR_NAMING_VIOLATION;
609 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
610 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
611 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
612 return LDB_ERR_UNWILLING_TO_PERFORM;
615 if (!ldb_msg_find_element(msg, "objectCategory")) {
616 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
617 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
618 /* Strip off extended components */
619 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
620 value = ldb_dn_alloc_linearized(msg, dn);
623 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
627 talloc_free(mem_ctx);
628 return LDB_ERR_OPERATIONS_ERROR;
630 ldb_msg_add_string(msg, "objectCategory", value);
632 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
633 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
637 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
638 el = ldb_msg_find_element(msg, "systemFlags");
640 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
643 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
644 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
645 ldb_msg_remove_element(msg, el);
648 /* This flag is only allowed on attributeSchema objects */
649 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
650 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
653 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
654 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
655 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
656 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
657 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
658 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
660 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
661 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
662 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
663 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
666 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
668 if (el || systemFlags != 0) {
669 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
673 talloc_free(mem_ctx);
674 ret = ldb_msg_sanity_check(ldb, msg);
677 if (ret != LDB_SUCCESS) {
681 ret = ldb_build_add_req(&add_req, ldb, ac,
686 if (ret != LDB_SUCCESS) {
690 /* perform the add */
691 return ldb_next_request(ac->module, add_req);
694 static int oc_modify_callback(struct ldb_request *req,
695 struct ldb_reply *ares);
696 static int objectclass_do_mod(struct oc_context *ac);
698 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
700 struct ldb_context *ldb = ldb_module_get_ctx(module);
701 struct ldb_message_element *objectclass_element;
702 struct ldb_message *msg;
703 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
704 struct class_list *sorted, *current;
705 struct ldb_request *down_req;
706 struct oc_context *ac;
711 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
713 /* do not manipulate our control entries */
714 if (ldb_dn_is_special(req->op.mod.message->dn)) {
715 return ldb_next_request(module, req);
718 /* Without schema, there isn't much to do here */
720 return ldb_next_request(module, req);
723 /* As with the "real" AD we don't accept empty messages */
724 if (req->op.mod.message->num_elements == 0) {
725 ldb_set_errstring(ldb, "objectclass: modify message must have "
726 "elements/attributes!");
727 return LDB_ERR_UNWILLING_TO_PERFORM;
730 ac = oc_init_context(module, req);
733 return LDB_ERR_OPERATIONS_ERROR;
736 if (!talloc_reference(ac, schema)) {
738 return LDB_ERR_OPERATIONS_ERROR;
741 /* If no part of this touches the objectClass, then we don't
742 * need to make any changes. */
743 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
745 /* If the only operation is the deletion of the objectClass
746 * then go on with just fixing the attribute case */
747 if (!objectclass_element) {
748 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
750 return LDB_ERR_OPERATIONS_ERROR;
753 ret = fix_check_attributes(ldb, schema, msg, req->operation);
754 if (ret != LDB_SUCCESS) {
758 ret = ldb_build_mod_req(&down_req, ldb, ac,
763 if (ret != LDB_SUCCESS) {
767 /* go on with the call chain */
768 return ldb_next_request(module, down_req);
771 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
772 case LDB_FLAG_MOD_DELETE:
773 if (objectclass_element->num_values == 0) {
774 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
778 case LDB_FLAG_MOD_REPLACE:
779 mem_ctx = talloc_new(ac);
780 if (mem_ctx == NULL) {
781 return LDB_ERR_OPERATIONS_ERROR;
784 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
786 talloc_free(mem_ctx);
787 return LDB_ERR_OPERATIONS_ERROR;
790 ret = fix_check_attributes(ldb, schema, msg, req->operation);
791 if (ret != LDB_SUCCESS) {
792 talloc_free(mem_ctx);
796 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
797 if (ret != LDB_SUCCESS) {
798 talloc_free(mem_ctx);
802 /* We must completely replace the existing objectClass entry,
803 * because we need it sorted */
805 ldb_msg_remove_attr(msg, "objectClass");
806 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
808 if (ret != LDB_SUCCESS) {
809 talloc_free(mem_ctx);
813 /* Move from the linked list back into an ldb msg */
814 for (current = sorted; current; current = current->next) {
815 /* copy the value as this string is on the schema
816 * context and we can't rely on it not changing
817 * before the operation is over */
818 value = talloc_strdup(msg,
819 current->objectclass->lDAPDisplayName);
822 talloc_free(mem_ctx);
823 return LDB_ERR_OPERATIONS_ERROR;
825 ret = ldb_msg_add_string(msg, "objectClass", value);
826 if (ret != LDB_SUCCESS) {
827 ldb_set_errstring(ldb,
828 "objectclass: could not re-add sorted "
829 "objectclass to modify msg");
830 talloc_free(mem_ctx);
835 talloc_free(mem_ctx);
837 ret = ldb_msg_sanity_check(ldb, msg);
838 if (ret != LDB_SUCCESS) {
842 ret = ldb_build_mod_req(&down_req, ldb, ac,
847 if (ret != LDB_SUCCESS) {
851 /* go on with the call chain */
852 return ldb_next_request(module, down_req);
855 /* This isn't the default branch of the switch, but a 'in any
856 * other case'. When a delete isn't for all objectClasses for
860 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
863 return LDB_ERR_OPERATIONS_ERROR;
866 ret = fix_check_attributes(ldb, schema, msg, req->operation);
867 if (ret != LDB_SUCCESS) {
872 ret = ldb_build_mod_req(&down_req, ldb, ac,
875 ac, oc_modify_callback,
877 if (ret != LDB_SUCCESS) {
881 return ldb_next_request(module, down_req);
884 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
886 struct ldb_context *ldb;
887 static const char * const attrs[] = { "objectClass", NULL };
888 struct ldb_request *search_req;
889 struct oc_context *ac;
892 ac = talloc_get_type(req->context, struct oc_context);
893 ldb = ldb_module_get_ctx(ac->module);
896 return ldb_module_done(ac->req, NULL, NULL,
897 LDB_ERR_OPERATIONS_ERROR);
900 if (ares->type == LDB_REPLY_REFERRAL) {
901 return ldb_module_send_referral(ac->req, ares->referral);
904 if (ares->error != LDB_SUCCESS) {
905 return ldb_module_done(ac->req, ares->controls,
906 ares->response, ares->error);
909 if (ares->type != LDB_REPLY_DONE) {
911 return ldb_module_done(ac->req, NULL, NULL,
912 LDB_ERR_OPERATIONS_ERROR);
917 ret = ldb_build_search_req(&search_req, ldb, ac,
918 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
921 ac, get_search_callback,
923 if (ret != LDB_SUCCESS) {
924 return ldb_module_done(ac->req, NULL, NULL, ret);
927 ac->step_fn = objectclass_do_mod;
929 ret = ldb_next_request(ac->module, search_req);
930 if (ret != LDB_SUCCESS) {
931 return ldb_module_done(ac->req, NULL, NULL, ret);
936 static int objectclass_do_mod(struct oc_context *ac)
938 struct ldb_context *ldb;
939 const struct dsdb_schema *schema;
940 struct ldb_request *mod_req;
942 struct ldb_message_element *objectclass_element;
943 struct ldb_message *msg;
945 struct class_list *sorted, *current;
948 ldb = ldb_module_get_ctx(ac->module);
950 if (ac->search_res == NULL) {
951 return LDB_ERR_OPERATIONS_ERROR;
953 schema = dsdb_get_schema(ldb, ac);
955 mem_ctx = talloc_new(ac);
956 if (mem_ctx == NULL) {
957 return LDB_ERR_OPERATIONS_ERROR;
960 /* use a new message structure */
961 msg = ldb_msg_new(ac);
963 ldb_set_errstring(ldb,
964 "objectclass: could not create new modify msg");
965 talloc_free(mem_ctx);
966 return LDB_ERR_OPERATIONS_ERROR;
969 /* This is now the objectClass list from the database */
970 objectclass_element = ldb_msg_find_element(ac->search_res->message,
972 if (!objectclass_element) {
973 /* Where did it go? bail now... */
974 talloc_free(mem_ctx);
975 return LDB_ERR_OPERATIONS_ERROR;
979 msg->dn = ac->req->op.mod.message->dn;
981 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
982 if (ret != LDB_SUCCESS) {
986 /* We must completely replace the existing objectClass entry.
987 * We could do a constrained add/del, but we are meant to be
988 * in a transaction... */
990 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
991 if (ret != LDB_SUCCESS) {
992 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
993 talloc_free(mem_ctx);
997 /* Move from the linked list back into an ldb msg */
998 for (current = sorted; current; current = current->next) {
999 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
1000 if (value == NULL) {
1002 return LDB_ERR_OPERATIONS_ERROR;
1004 ret = ldb_msg_add_string(msg, "objectClass", value);
1005 if (ret != LDB_SUCCESS) {
1006 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1007 talloc_free(mem_ctx);
1012 ret = ldb_msg_sanity_check(ldb, msg);
1013 if (ret != LDB_SUCCESS) {
1014 talloc_free(mem_ctx);
1018 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1023 if (ret != LDB_SUCCESS) {
1024 talloc_free(mem_ctx);
1028 talloc_free(mem_ctx);
1029 /* perform the modify */
1030 return ldb_next_request(ac->module, mod_req);
1033 static int objectclass_do_rename(struct oc_context *ac);
1035 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1037 static const char * const attrs[] = { NULL };
1038 struct ldb_context *ldb;
1039 struct ldb_request *search_req;
1040 struct oc_context *ac;
1041 struct ldb_dn *parent_dn;
1044 ldb = ldb_module_get_ctx(module);
1046 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1048 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1049 return ldb_next_request(module, req);
1052 /* Firstly ensure we are not trying to rename it to be a child of itself */
1053 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1054 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1055 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1056 ldb_dn_get_linearized(req->op.rename.olddn));
1057 return LDB_ERR_UNWILLING_TO_PERFORM;
1060 ac = oc_init_context(module, req);
1062 return LDB_ERR_OPERATIONS_ERROR;
1065 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1066 if (parent_dn == NULL) {
1068 return LDB_ERR_OPERATIONS_ERROR;
1072 it makes a search request, looking for the parent DN to fix up the new DN
1073 to a standard one, at objectclass_do_rename()
1075 ret = ldb_build_search_req(&search_req, ldb,
1076 ac, parent_dn, LDB_SCOPE_BASE,
1079 ac, get_search_callback,
1081 if (ret != LDB_SUCCESS) {
1085 /* we have to add the show deleted control, as otherwise DRS
1086 deletes will be refused as we will think the target parent
1088 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1090 if (ret != LDB_SUCCESS) {
1094 ac->step_fn = objectclass_do_rename;
1096 return ldb_next_request(ac->module, search_req);
1101 static int objectclass_do_rename(struct oc_context *ac)
1103 struct ldb_context *ldb;
1104 struct ldb_request *rename_req;
1105 struct ldb_dn *fixed_dn;
1108 ldb = ldb_module_get_ctx(ac->module);
1110 /* Check we have a valid parent */
1111 if (ac->search_res == NULL) {
1112 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1113 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1114 return LDB_ERR_UNWILLING_TO_PERFORM;
1117 /* Fix up the DN to be in the standard form,
1118 * taking particular care to match the parent DN */
1120 ac->req->op.rename.newdn,
1121 ac->search_res->message->dn,
1123 if (ret != LDB_SUCCESS) {
1127 /* TODO: Check this is a valid child to this parent,
1128 * by reading the allowedChildClasses and
1129 * allowedChildClasssesEffective attributes */
1131 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1132 ac->req->op.rename.olddn, fixed_dn,
1136 if (ret != LDB_SUCCESS) {
1140 /* perform the rename */
1141 return ldb_next_request(ac->module, rename_req);
1144 static int objectclass_init(struct ldb_module *module)
1146 struct ldb_context *ldb = ldb_module_get_ctx(module);
1148 /* Init everything else */
1149 ret = ldb_next_init(module);
1150 if (ret != LDB_SUCCESS) {
1154 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1155 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1160 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1161 .name = "objectclass",
1162 .add = objectclass_add,
1163 .modify = objectclass_modify,
1164 .rename = objectclass_rename,
1165 .init_context = objectclass_init