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);
75 ldb_set_errstring(ldb, "Out of Memory");
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);
735 return LDB_ERR_OPERATIONS_ERROR;
738 if (!talloc_reference(ac, schema)) {
740 return LDB_ERR_OPERATIONS_ERROR;
743 /* If no part of this touches the objectClass, then we don't
744 * need to make any changes. */
745 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
747 /* If the only operation is the deletion of the objectClass
748 * then go on with just fixing the attribute case */
749 if (!objectclass_element) {
750 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
752 return LDB_ERR_OPERATIONS_ERROR;
755 ret = fix_check_attributes(ldb, schema, msg, req->operation);
756 if (ret != LDB_SUCCESS) {
760 ret = ldb_build_mod_req(&down_req, ldb, ac,
765 if (ret != LDB_SUCCESS) {
769 /* go on with the call chain */
770 return ldb_next_request(module, down_req);
773 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
774 case LDB_FLAG_MOD_DELETE:
775 if (objectclass_element->num_values == 0) {
776 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
780 case LDB_FLAG_MOD_REPLACE:
781 mem_ctx = talloc_new(ac);
782 if (mem_ctx == NULL) {
783 return LDB_ERR_OPERATIONS_ERROR;
786 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
788 talloc_free(mem_ctx);
789 return LDB_ERR_OPERATIONS_ERROR;
792 ret = fix_check_attributes(ldb, schema, msg, req->operation);
793 if (ret != LDB_SUCCESS) {
794 talloc_free(mem_ctx);
798 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
799 if (ret != LDB_SUCCESS) {
800 talloc_free(mem_ctx);
804 /* We must completely replace the existing objectClass entry,
805 * because we need it sorted */
807 ldb_msg_remove_attr(msg, "objectClass");
808 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
810 if (ret != LDB_SUCCESS) {
811 talloc_free(mem_ctx);
815 /* Move from the linked list back into an ldb msg */
816 for (current = sorted; current; current = current->next) {
817 /* copy the value as this string is on the schema
818 * context and we can't rely on it not changing
819 * before the operation is over */
820 value = talloc_strdup(msg,
821 current->objectclass->lDAPDisplayName);
824 talloc_free(mem_ctx);
825 return LDB_ERR_OPERATIONS_ERROR;
827 ret = ldb_msg_add_string(msg, "objectClass", value);
828 if (ret != LDB_SUCCESS) {
829 ldb_set_errstring(ldb,
830 "objectclass: could not re-add sorted "
831 "objectclass to modify msg");
832 talloc_free(mem_ctx);
837 talloc_free(mem_ctx);
839 ret = ldb_msg_sanity_check(ldb, msg);
840 if (ret != LDB_SUCCESS) {
844 ret = ldb_build_mod_req(&down_req, ldb, ac,
849 if (ret != LDB_SUCCESS) {
853 /* go on with the call chain */
854 return ldb_next_request(module, down_req);
857 /* This isn't the default branch of the switch, but a 'in any
858 * other case'. When a delete isn't for all objectClasses for
862 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
865 return LDB_ERR_OPERATIONS_ERROR;
868 ret = fix_check_attributes(ldb, schema, msg, req->operation);
869 if (ret != LDB_SUCCESS) {
874 ret = ldb_build_mod_req(&down_req, ldb, ac,
877 ac, oc_modify_callback,
879 if (ret != LDB_SUCCESS) {
883 return ldb_next_request(module, down_req);
886 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
888 struct ldb_context *ldb;
889 static const char * const attrs[] = { "objectClass", NULL };
890 struct ldb_request *search_req;
891 struct oc_context *ac;
894 ac = talloc_get_type(req->context, struct oc_context);
895 ldb = ldb_module_get_ctx(ac->module);
898 return ldb_module_done(ac->req, NULL, NULL,
899 LDB_ERR_OPERATIONS_ERROR);
902 if (ares->type == LDB_REPLY_REFERRAL) {
903 return ldb_module_send_referral(ac->req, ares->referral);
906 if (ares->error != LDB_SUCCESS) {
907 return ldb_module_done(ac->req, ares->controls,
908 ares->response, ares->error);
911 if (ares->type != LDB_REPLY_DONE) {
913 return ldb_module_done(ac->req, NULL, NULL,
914 LDB_ERR_OPERATIONS_ERROR);
919 ret = ldb_build_search_req(&search_req, ldb, ac,
920 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
923 ac, get_search_callback,
925 if (ret != LDB_SUCCESS) {
926 return ldb_module_done(ac->req, NULL, NULL, ret);
929 ac->step_fn = objectclass_do_mod;
931 ret = ldb_next_request(ac->module, search_req);
932 if (ret != LDB_SUCCESS) {
933 return ldb_module_done(ac->req, NULL, NULL, ret);
938 static int objectclass_do_mod(struct oc_context *ac)
940 struct ldb_context *ldb;
941 const struct dsdb_schema *schema;
942 struct ldb_request *mod_req;
944 struct ldb_message_element *objectclass_element;
945 struct ldb_message *msg;
947 struct class_list *sorted, *current;
950 ldb = ldb_module_get_ctx(ac->module);
952 if (ac->search_res == NULL) {
953 return LDB_ERR_OPERATIONS_ERROR;
955 schema = dsdb_get_schema(ldb, ac);
957 mem_ctx = talloc_new(ac);
958 if (mem_ctx == NULL) {
959 return LDB_ERR_OPERATIONS_ERROR;
962 /* use a new message structure */
963 msg = ldb_msg_new(ac);
965 ldb_set_errstring(ldb,
966 "objectclass: could not create new modify msg");
967 talloc_free(mem_ctx);
968 return LDB_ERR_OPERATIONS_ERROR;
971 /* This is now the objectClass list from the database */
972 objectclass_element = ldb_msg_find_element(ac->search_res->message,
974 if (!objectclass_element) {
975 /* Where did it go? bail now... */
976 talloc_free(mem_ctx);
977 return LDB_ERR_OPERATIONS_ERROR;
981 msg->dn = ac->req->op.mod.message->dn;
983 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
984 if (ret != LDB_SUCCESS) {
988 /* We must completely replace the existing objectClass entry.
989 * We could do a constrained add/del, but we are meant to be
990 * in a transaction... */
992 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
993 if (ret != LDB_SUCCESS) {
994 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
995 talloc_free(mem_ctx);
999 /* Move from the linked list back into an ldb msg */
1000 for (current = sorted; current; current = current->next) {
1001 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
1002 if (value == NULL) {
1004 return LDB_ERR_OPERATIONS_ERROR;
1006 ret = ldb_msg_add_string(msg, "objectClass", value);
1007 if (ret != LDB_SUCCESS) {
1008 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1009 talloc_free(mem_ctx);
1014 ret = ldb_msg_sanity_check(ldb, msg);
1015 if (ret != LDB_SUCCESS) {
1016 talloc_free(mem_ctx);
1020 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1025 if (ret != LDB_SUCCESS) {
1026 talloc_free(mem_ctx);
1030 talloc_free(mem_ctx);
1031 /* perform the modify */
1032 return ldb_next_request(ac->module, mod_req);
1035 static int objectclass_do_rename(struct oc_context *ac);
1037 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1039 static const char * const attrs[] = { NULL };
1040 struct ldb_context *ldb;
1041 struct ldb_request *search_req;
1042 struct oc_context *ac;
1043 struct ldb_dn *parent_dn;
1046 ldb = ldb_module_get_ctx(module);
1048 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1050 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1051 return ldb_next_request(module, req);
1054 /* Firstly ensure we are not trying to rename it to be a child of itself */
1055 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1056 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1057 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1058 ldb_dn_get_linearized(req->op.rename.olddn));
1059 return LDB_ERR_UNWILLING_TO_PERFORM;
1062 ac = oc_init_context(module, req);
1064 return LDB_ERR_OPERATIONS_ERROR;
1067 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1068 if (parent_dn == NULL) {
1070 return LDB_ERR_OPERATIONS_ERROR;
1074 it makes a search request, looking for the parent DN to fix up the new DN
1075 to a standard one, at objectclass_do_rename()
1077 ret = ldb_build_search_req(&search_req, ldb,
1078 ac, parent_dn, LDB_SCOPE_BASE,
1081 ac, get_search_callback,
1083 if (ret != LDB_SUCCESS) {
1087 /* we have to add the show deleted control, as otherwise DRS
1088 deletes will be refused as we will think the target parent
1090 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1092 if (ret != LDB_SUCCESS) {
1096 ac->step_fn = objectclass_do_rename;
1098 return ldb_next_request(ac->module, search_req);
1103 static int objectclass_do_rename(struct oc_context *ac)
1105 struct ldb_context *ldb;
1106 struct ldb_request *rename_req;
1107 struct ldb_dn *fixed_dn;
1110 ldb = ldb_module_get_ctx(ac->module);
1112 /* Check we have a valid parent */
1113 if (ac->search_res == NULL) {
1114 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1115 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1116 return LDB_ERR_UNWILLING_TO_PERFORM;
1119 /* Fix up the DN to be in the standard form,
1120 * taking particular care to match the parent DN */
1122 ac->req->op.rename.newdn,
1123 ac->search_res->message->dn,
1125 if (ret != LDB_SUCCESS) {
1129 /* TODO: Check this is a valid child to this parent,
1130 * by reading the allowedChildClasses and
1131 * allowedChildClasssesEffective attributes */
1133 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1134 ac->req->op.rename.olddn, fixed_dn,
1138 if (ret != LDB_SUCCESS) {
1142 /* perform the rename */
1143 return ldb_next_request(ac->module, rename_req);
1146 static int objectclass_init(struct ldb_module *module)
1148 struct ldb_context *ldb = ldb_module_get_ctx(module);
1150 /* Init everything else */
1151 ret = ldb_next_init(module);
1152 if (ret != LDB_SUCCESS) {
1156 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1157 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1162 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1163 .name = "objectclass",
1164 .add = objectclass_add,
1165 .modify = objectclass_modify,
1166 .rename = objectclass_rename,
1167 .init_context = objectclass_init