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) {
440 talloc_steal(search_req, parent_dn);
442 ac->step_fn = objectclass_do_add;
444 return ldb_next_request(ac->module, search_req);
447 static int objectclass_do_add(struct oc_context *ac)
449 struct ldb_context *ldb;
450 const struct dsdb_schema *schema;
451 struct ldb_request *add_req;
453 struct ldb_message_element *objectclass_element, *el;
454 struct ldb_message *msg;
456 struct class_list *sorted, *current;
458 const struct dsdb_class *objectclass;
459 int32_t systemFlags = 0;
460 const char *rdn_name = NULL;
462 ldb = ldb_module_get_ctx(ac->module);
463 schema = dsdb_get_schema(ldb, ac);
465 mem_ctx = talloc_new(ac);
466 if (mem_ctx == NULL) {
468 return LDB_ERR_OPERATIONS_ERROR;
471 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
473 /* Check we have a valid parent */
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 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_check_attributes(ldb, schema, msg, ac->req->operation);
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);
552 /* Retrive the message again so get_last_structural_class works */
553 objectclass_element = ldb_msg_find_element(msg, "objectClass");
555 /* Make sure its valid to add an object of this type */
556 objectclass = get_last_structural_class(schema,objectclass_element);
557 if(objectclass == NULL) {
558 ldb_asprintf_errstring(ldb,
559 "Failed to find a structural class for %s",
560 ldb_dn_get_linearized(msg->dn));
561 return LDB_ERR_NAMING_VIOLATION;
564 rdn_name = ldb_dn_get_rdn_name(msg->dn);
565 if (objectclass->rDNAttID
566 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
567 ldb_asprintf_errstring(ldb,
568 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
569 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
570 return LDB_ERR_NAMING_VIOLATION;
573 if (ac->search_res && ac->search_res->message) {
574 struct ldb_message_element *oc_el
575 = ldb_msg_find_element(ac->search_res->message, "objectClass");
577 bool allowed_class = false;
579 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
580 const struct dsdb_class *sclass;
582 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
584 /* We don't know this class? what is going on? */
587 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
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;
595 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
596 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
597 allowed_class = true;
604 if (!allowed_class) {
605 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
606 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
607 return LDB_ERR_NAMING_VIOLATION;
611 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
612 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
613 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
614 return LDB_ERR_UNWILLING_TO_PERFORM;
617 if (!ldb_msg_find_element(msg, "objectCategory")) {
618 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
619 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
620 /* Strip off extended components */
621 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
622 value = ldb_dn_alloc_linearized(msg, dn);
625 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
629 talloc_free(mem_ctx);
630 return LDB_ERR_OPERATIONS_ERROR;
632 ldb_msg_add_string(msg, "objectCategory", value);
634 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
635 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
639 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
640 el = ldb_msg_find_element(msg, "systemFlags");
642 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
645 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
646 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
647 ldb_msg_remove_element(msg, el);
650 /* This flag is only allowed on attributeSchema objects */
651 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
652 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
655 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
656 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
657 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
658 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
659 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
660 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
662 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
663 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
664 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
665 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
668 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
670 if (el || systemFlags != 0) {
671 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
675 talloc_free(mem_ctx);
676 ret = ldb_msg_sanity_check(ldb, msg);
679 if (ret != LDB_SUCCESS) {
683 ret = ldb_build_add_req(&add_req, ldb, ac,
688 if (ret != LDB_SUCCESS) {
692 /* perform the add */
693 return ldb_next_request(ac->module, add_req);
696 static int oc_modify_callback(struct ldb_request *req,
697 struct ldb_reply *ares);
698 static int objectclass_do_mod(struct oc_context *ac);
700 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
702 struct ldb_context *ldb = ldb_module_get_ctx(module);
703 struct ldb_message_element *objectclass_element;
704 struct ldb_message *msg;
705 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
706 struct class_list *sorted, *current;
707 struct ldb_request *down_req;
708 struct oc_context *ac;
713 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
715 /* do not manipulate our control entries */
716 if (ldb_dn_is_special(req->op.mod.message->dn)) {
717 return ldb_next_request(module, req);
720 /* Without schema, there isn't much to do here */
722 return ldb_next_request(module, req);
725 /* As with the "real" AD we don't accept empty messages */
726 if (req->op.mod.message->num_elements == 0) {
727 ldb_set_errstring(ldb, "objectclass: modify message must have "
728 "elements/attributes!");
729 return LDB_ERR_UNWILLING_TO_PERFORM;
732 ac = oc_init_context(module, req);
734 return LDB_ERR_OPERATIONS_ERROR;
737 if (!talloc_reference(ac, schema)) {
739 return LDB_ERR_OPERATIONS_ERROR;
742 /* If no part of this touches the objectClass, then we don't
743 * need to make any changes. */
744 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
746 /* If the only operation is the deletion of the objectClass
747 * then go on with just fixing the attribute case */
748 if (!objectclass_element) {
749 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
751 return LDB_ERR_OPERATIONS_ERROR;
754 ret = fix_check_attributes(ldb, schema, msg, req->operation);
755 if (ret != LDB_SUCCESS) {
759 ret = ldb_build_mod_req(&down_req, ldb, ac,
764 if (ret != LDB_SUCCESS) {
768 /* go on with the call chain */
769 return ldb_next_request(module, down_req);
772 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
773 case LDB_FLAG_MOD_DELETE:
774 if (objectclass_element->num_values == 0) {
775 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
779 case LDB_FLAG_MOD_REPLACE:
780 mem_ctx = talloc_new(ac);
781 if (mem_ctx == NULL) {
782 return LDB_ERR_OPERATIONS_ERROR;
785 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
787 talloc_free(mem_ctx);
788 return LDB_ERR_OPERATIONS_ERROR;
791 ret = fix_check_attributes(ldb, schema, msg, req->operation);
792 if (ret != LDB_SUCCESS) {
793 talloc_free(mem_ctx);
797 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
798 if (ret != LDB_SUCCESS) {
799 talloc_free(mem_ctx);
803 /* We must completely replace the existing objectClass entry,
804 * because we need it sorted */
806 ldb_msg_remove_attr(msg, "objectClass");
807 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
809 if (ret != LDB_SUCCESS) {
810 talloc_free(mem_ctx);
814 /* Move from the linked list back into an ldb msg */
815 for (current = sorted; current; current = current->next) {
816 /* copy the value as this string is on the schema
817 * context and we can't rely on it not changing
818 * before the operation is over */
819 value = talloc_strdup(msg,
820 current->objectclass->lDAPDisplayName);
823 talloc_free(mem_ctx);
824 return LDB_ERR_OPERATIONS_ERROR;
826 ret = ldb_msg_add_string(msg, "objectClass", value);
827 if (ret != LDB_SUCCESS) {
828 ldb_set_errstring(ldb,
829 "objectclass: could not re-add sorted "
830 "objectclass to modify msg");
831 talloc_free(mem_ctx);
836 talloc_free(mem_ctx);
838 ret = ldb_msg_sanity_check(ldb, msg);
839 if (ret != LDB_SUCCESS) {
843 ret = ldb_build_mod_req(&down_req, ldb, ac,
848 if (ret != LDB_SUCCESS) {
852 /* go on with the call chain */
853 return ldb_next_request(module, down_req);
856 /* This isn't the default branch of the switch, but a 'in any
857 * other case'. When a delete isn't for all objectClasses for
861 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
864 return LDB_ERR_OPERATIONS_ERROR;
867 ret = fix_check_attributes(ldb, schema, msg, req->operation);
868 if (ret != LDB_SUCCESS) {
873 ret = ldb_build_mod_req(&down_req, ldb, ac,
876 ac, oc_modify_callback,
878 if (ret != LDB_SUCCESS) {
882 return ldb_next_request(module, down_req);
885 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
887 struct ldb_context *ldb;
888 static const char * const attrs[] = { "objectClass", NULL };
889 struct ldb_request *search_req;
890 struct oc_context *ac;
893 ac = talloc_get_type(req->context, struct oc_context);
894 ldb = ldb_module_get_ctx(ac->module);
897 return ldb_module_done(ac->req, NULL, NULL,
898 LDB_ERR_OPERATIONS_ERROR);
901 if (ares->type == LDB_REPLY_REFERRAL) {
902 return ldb_module_send_referral(ac->req, ares->referral);
905 if (ares->error != LDB_SUCCESS) {
906 return ldb_module_done(ac->req, ares->controls,
907 ares->response, ares->error);
910 if (ares->type != LDB_REPLY_DONE) {
912 return ldb_module_done(ac->req, NULL, NULL,
913 LDB_ERR_OPERATIONS_ERROR);
918 ret = ldb_build_search_req(&search_req, ldb, ac,
919 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
922 ac, get_search_callback,
924 if (ret != LDB_SUCCESS) {
925 return ldb_module_done(ac->req, NULL, NULL, ret);
928 ac->step_fn = objectclass_do_mod;
930 ret = ldb_next_request(ac->module, search_req);
931 if (ret != LDB_SUCCESS) {
932 return ldb_module_done(ac->req, NULL, NULL, ret);
937 static int objectclass_do_mod(struct oc_context *ac)
939 struct ldb_context *ldb;
940 const struct dsdb_schema *schema;
941 struct ldb_request *mod_req;
943 struct ldb_message_element *objectclass_element;
944 struct ldb_message *msg;
946 struct class_list *sorted, *current;
949 ldb = ldb_module_get_ctx(ac->module);
951 if (ac->search_res == NULL) {
952 return LDB_ERR_OPERATIONS_ERROR;
954 schema = dsdb_get_schema(ldb, ac);
956 mem_ctx = talloc_new(ac);
957 if (mem_ctx == NULL) {
958 return LDB_ERR_OPERATIONS_ERROR;
961 /* use a new message structure */
962 msg = ldb_msg_new(ac);
964 ldb_set_errstring(ldb,
965 "objectclass: could not create new modify msg");
966 talloc_free(mem_ctx);
967 return LDB_ERR_OPERATIONS_ERROR;
970 /* This is now the objectClass list from the database */
971 objectclass_element = ldb_msg_find_element(ac->search_res->message,
973 if (!objectclass_element) {
974 /* Where did it go? bail now... */
975 talloc_free(mem_ctx);
976 return LDB_ERR_OPERATIONS_ERROR;
980 msg->dn = ac->req->op.mod.message->dn;
982 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
983 if (ret != LDB_SUCCESS) {
987 /* We must completely replace the existing objectClass entry.
988 * We could do a constrained add/del, but we are meant to be
989 * in a transaction... */
991 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
992 if (ret != LDB_SUCCESS) {
993 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
994 talloc_free(mem_ctx);
998 /* Move from the linked list back into an ldb msg */
999 for (current = sorted; current; current = current->next) {
1000 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
1001 if (value == NULL) {
1003 return LDB_ERR_OPERATIONS_ERROR;
1005 ret = ldb_msg_add_string(msg, "objectClass", value);
1006 if (ret != LDB_SUCCESS) {
1007 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1008 talloc_free(mem_ctx);
1013 ret = ldb_msg_sanity_check(ldb, msg);
1014 if (ret != LDB_SUCCESS) {
1015 talloc_free(mem_ctx);
1019 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1024 if (ret != LDB_SUCCESS) {
1025 talloc_free(mem_ctx);
1029 talloc_free(mem_ctx);
1030 /* perform the modify */
1031 return ldb_next_request(ac->module, mod_req);
1034 static int objectclass_do_rename(struct oc_context *ac);
1036 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1038 static const char * const attrs[] = { NULL };
1039 struct ldb_context *ldb;
1040 struct ldb_request *search_req;
1041 struct oc_context *ac;
1042 struct ldb_dn *parent_dn;
1045 ldb = ldb_module_get_ctx(module);
1047 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1049 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1050 return ldb_next_request(module, req);
1053 /* Firstly ensure we are not trying to rename it to be a child of itself */
1054 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1055 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1056 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1057 ldb_dn_get_linearized(req->op.rename.olddn));
1058 return LDB_ERR_UNWILLING_TO_PERFORM;
1061 ac = oc_init_context(module, req);
1063 return LDB_ERR_OPERATIONS_ERROR;
1066 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1067 if (parent_dn == NULL) {
1069 return LDB_ERR_OPERATIONS_ERROR;
1073 it makes a search request, looking for the parent DN to fix up the new DN
1074 to a standard one, at objectclass_do_rename()
1076 ret = ldb_build_search_req(&search_req, ldb,
1077 ac, parent_dn, LDB_SCOPE_BASE,
1080 ac, get_search_callback,
1082 if (ret != LDB_SUCCESS) {
1086 /* we have to add the show deleted control, as otherwise DRS
1087 deletes will be refused as we will think the target parent
1089 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1091 if (ret != LDB_SUCCESS) {
1095 ac->step_fn = objectclass_do_rename;
1097 return ldb_next_request(ac->module, search_req);
1102 static int objectclass_do_rename(struct oc_context *ac)
1104 struct ldb_context *ldb;
1105 struct ldb_request *rename_req;
1106 struct ldb_dn *fixed_dn;
1109 ldb = ldb_module_get_ctx(ac->module);
1111 /* Check we have a valid parent */
1112 if (ac->search_res == NULL) {
1113 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1114 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1115 return LDB_ERR_UNWILLING_TO_PERFORM;
1118 /* Fix up the DN to be in the standard form,
1119 * taking particular care to match the parent DN */
1121 ac->req->op.rename.newdn,
1122 ac->search_res->message->dn,
1124 if (ret != LDB_SUCCESS) {
1128 /* TODO: Check this is a valid child to this parent,
1129 * by reading the allowedChildClasses and
1130 * allowedChildClasssesEffective attributes */
1132 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1133 ac->req->op.rename.olddn, fixed_dn,
1137 if (ret != LDB_SUCCESS) {
1141 /* perform the rename */
1142 return ldb_next_request(ac->module, rename_req);
1145 static int objectclass_init(struct ldb_module *module)
1147 struct ldb_context *ldb = ldb_module_get_ctx(module);
1149 /* Init everything else */
1150 ret = ldb_next_init(module);
1151 if (ret != LDB_SUCCESS) {
1155 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1156 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1161 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1162 .name = "objectclass",
1163 .add = objectclass_add,
1164 .modify = objectclass_modify,
1165 .rename = objectclass_rename,
1166 .init_context = objectclass_init