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;
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);
277 if (ares->error != LDB_SUCCESS) {
278 return ldb_module_done(ac->req, ares->controls,
279 ares->response, ares->error);
282 if (ares->type != LDB_REPLY_DONE) {
284 return ldb_module_done(ac->req, NULL, NULL,
285 LDB_ERR_OPERATIONS_ERROR);
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
294 This should mean that if the parent is:
295 CN=Users,DC=samba,DC=example,DC=com
296 and a proposed child is
297 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
299 The resulting DN should be:
301 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
304 static int fix_dn(TALLOC_CTX *mem_ctx,
305 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
306 struct ldb_dn **fixed_dn)
308 char *upper_rdn_attr;
309 const struct ldb_val *rdn_val;
311 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
312 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
314 /* We need the attribute name in upper case */
315 upper_rdn_attr = strupper_talloc(*fixed_dn,
316 ldb_dn_get_rdn_name(newdn));
317 if (!upper_rdn_attr) {
318 return LDB_ERR_OPERATIONS_ERROR;
321 /* Create a new child */
322 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
323 return LDB_ERR_OPERATIONS_ERROR;
327 rdn_val = ldb_dn_get_rdn_val(newdn);
330 /* the rules for rDN length constraints are more complex than
331 this. Until we understand them we need to leave this
332 constraint out. Otherwise we break replication, as windows
333 does sometimes send us rDNs longer than 64 */
334 if (!rdn_val || rdn_val->length > 64) {
335 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
340 /* And replace it with CN=foo (we need the attribute in upper case */
341 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
344 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
345 static int fix_check_attributes(struct ldb_context *ldb,
346 const struct dsdb_schema *schema,
347 struct ldb_message *msg,
348 enum ldb_request_type op)
351 for (i=0; i < msg->num_elements; i++) {
352 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
353 /* Add in a very special case for 'clearTextPassword',
354 * which is used for internal processing only, and is
355 * not presented in the schema */
357 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
358 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
359 /* Apparently Windows sends exactly this behaviour */
360 return LDB_ERR_NO_SUCH_ATTRIBUTE;
363 msg->elements[i].name = attribute->lDAPDisplayName;
365 /* We have to deny write operations on constructed attributes */
366 if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
368 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
370 return LDB_ERR_CONSTRAINT_VIOLATION;
380 static int objectclass_do_add(struct oc_context *ac);
382 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
384 struct ldb_context *ldb;
385 struct ldb_request *search_req;
386 struct oc_context *ac;
387 struct ldb_dn *parent_dn;
389 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
391 ldb = ldb_module_get_ctx(module);
393 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
395 /* do not manipulate our control entries */
396 if (ldb_dn_is_special(req->op.add.message->dn)) {
397 return ldb_next_request(module, req);
400 /* the objectClass must be specified on add */
401 if (ldb_msg_find_element(req->op.add.message,
402 "objectClass") == NULL) {
403 return LDB_ERR_OBJECT_CLASS_VIOLATION;
406 ac = oc_init_context(module, req);
408 return LDB_ERR_OPERATIONS_ERROR;
411 /* If there isn't a parent, just go on to the add processing */
412 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
413 return objectclass_do_add(ac);
416 /* get copy of parent DN */
417 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
418 if (parent_dn == NULL) {
420 return LDB_ERR_OPERATIONS_ERROR;
423 ret = ldb_build_search_req(&search_req, ldb,
424 ac, parent_dn, LDB_SCOPE_BASE,
425 "(objectClass=*)", parent_attrs,
427 ac, get_search_callback,
429 if (ret != LDB_SUCCESS) {
432 talloc_steal(search_req, parent_dn);
434 ac->step_fn = objectclass_do_add;
436 return ldb_next_request(ac->module, search_req);
439 static int objectclass_do_add(struct oc_context *ac)
441 struct ldb_context *ldb;
442 const struct dsdb_schema *schema;
443 struct ldb_request *add_req;
445 struct ldb_message_element *objectclass_element, *el;
446 struct ldb_message *msg;
448 struct class_list *sorted, *current;
450 const struct dsdb_class *objectclass;
451 int32_t systemFlags = 0;
452 const char *rdn_name = NULL;
454 ldb = ldb_module_get_ctx(ac->module);
455 schema = dsdb_get_schema(ldb);
457 mem_ctx = talloc_new(ac);
458 if (mem_ctx == NULL) {
459 return LDB_ERR_OPERATIONS_ERROR;
462 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
464 /* Check we have a valid parent */
465 if (ac->search_res == NULL) {
466 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
468 /* Allow the tree to be started */
470 /* but don't keep any error string, it's meaningless */
471 ldb_set_errstring(ldb, NULL);
473 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
474 ldb_dn_get_linearized(msg->dn));
475 talloc_free(mem_ctx);
476 return LDB_ERR_NO_SUCH_OBJECT;
480 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
482 ac->req->op.add.message->dn,
483 ac->search_res->message->dn,
486 if (ret != LDB_SUCCESS) {
487 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
488 ldb_dn_get_linearized(ac->req->op.add.message->dn));
489 talloc_free(mem_ctx);
495 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
496 if (ret != LDB_SUCCESS) {
497 talloc_free(mem_ctx);
501 /* This is now the objectClass list from the database */
502 objectclass_element = ldb_msg_find_element(msg, "objectClass");
504 if (!objectclass_element) {
505 /* Where did it go? bail now... */
506 talloc_free(mem_ctx);
507 return LDB_ERR_OPERATIONS_ERROR;
509 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
510 if (ret != LDB_SUCCESS) {
511 talloc_free(mem_ctx);
515 ldb_msg_remove_attr(msg, "objectClass");
516 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
518 if (ret != LDB_SUCCESS) {
519 talloc_free(mem_ctx);
523 /* We must completely replace the existing objectClass entry,
524 * because we need it sorted */
526 /* Move from the linked list back into an ldb msg */
527 for (current = sorted; current; current = current->next) {
528 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
531 talloc_free(mem_ctx);
532 return LDB_ERR_OPERATIONS_ERROR;
534 ret = ldb_msg_add_string(msg, "objectClass", value);
535 if (ret != LDB_SUCCESS) {
536 ldb_set_errstring(ldb,
537 "objectclass: could not re-add sorted "
538 "objectclass to modify msg");
539 talloc_free(mem_ctx);
544 /* Retrive the message again so get_last_structural_class works */
545 objectclass_element = ldb_msg_find_element(msg, "objectClass");
547 /* Make sure its valid to add an object of this type */
548 objectclass = get_last_structural_class(schema,objectclass_element);
549 if(objectclass == NULL) {
550 ldb_asprintf_errstring(ldb,
551 "Failed to find a structural class for %s",
552 ldb_dn_get_linearized(msg->dn));
553 return LDB_ERR_NAMING_VIOLATION;
556 rdn_name = ldb_dn_get_rdn_name(msg->dn);
557 if (objectclass->rDNAttID
558 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
559 ldb_asprintf_errstring(ldb,
560 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
561 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
562 return LDB_ERR_NAMING_VIOLATION;
565 if (ac->search_res && ac->search_res->message) {
566 struct ldb_message_element *oc_el
567 = ldb_msg_find_element(ac->search_res->message, "objectClass");
569 bool allowed_class = false;
571 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
572 const struct dsdb_class *sclass;
574 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
576 /* We don't know this class? what is going on? */
579 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
580 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
581 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
582 allowed_class = true;
587 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
588 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
589 allowed_class = true;
596 if (!allowed_class) {
597 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
598 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
599 return LDB_ERR_NAMING_VIOLATION;
603 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
604 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
605 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
606 return LDB_ERR_UNWILLING_TO_PERFORM;
609 if (!ldb_msg_find_element(msg, "objectCategory")) {
610 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
611 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
612 /* Strip off extended components */
613 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
614 value = ldb_dn_alloc_linearized(msg, dn);
617 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
621 talloc_free(mem_ctx);
622 return LDB_ERR_OPERATIONS_ERROR;
624 ldb_msg_add_string(msg, "objectCategory", value);
626 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
627 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
631 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
632 el = ldb_msg_find_element(msg, "systemFlags");
634 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
637 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
638 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
639 ldb_msg_remove_element(msg, el);
642 /* This flag is only allowed on attributeSchema objects */
643 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
644 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
647 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
648 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
649 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
650 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
651 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
652 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
654 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
655 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
656 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
657 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
660 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
662 if (el || systemFlags != 0) {
663 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
667 talloc_free(mem_ctx);
668 ret = ldb_msg_sanity_check(ldb, msg);
671 if (ret != LDB_SUCCESS) {
675 ret = ldb_build_add_req(&add_req, ldb, ac,
680 if (ret != LDB_SUCCESS) {
684 /* perform the add */
685 return ldb_next_request(ac->module, add_req);
688 static int oc_modify_callback(struct ldb_request *req,
689 struct ldb_reply *ares);
690 static int objectclass_do_mod(struct oc_context *ac);
692 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
694 struct ldb_context *ldb = ldb_module_get_ctx(module);
695 struct ldb_message_element *objectclass_element;
696 struct ldb_message *msg;
697 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
698 struct class_list *sorted, *current;
699 struct ldb_request *down_req;
700 struct oc_context *ac;
705 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
707 /* do not manipulate our control entries */
708 if (ldb_dn_is_special(req->op.mod.message->dn)) {
709 return ldb_next_request(module, req);
712 /* Without schema, there isn't much to do here */
714 return ldb_next_request(module, req);
717 /* As with the "real" AD we don't accept empty messages */
718 if (req->op.mod.message->num_elements == 0) {
719 ldb_set_errstring(ldb, "objectclass: modify message must have "
720 "elements/attributes!");
721 return LDB_ERR_UNWILLING_TO_PERFORM;
724 ac = oc_init_context(module, req);
726 return LDB_ERR_OPERATIONS_ERROR;
729 /* If no part of this touches the objectClass, then we don't
730 * need to make any changes. */
731 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
733 /* If the only operation is the deletion of the objectClass
734 * then go on with just fixing the attribute case */
735 if (!objectclass_element) {
736 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
738 return LDB_ERR_OPERATIONS_ERROR;
741 ret = fix_check_attributes(ldb, schema, msg, req->operation);
742 if (ret != LDB_SUCCESS) {
746 ret = ldb_build_mod_req(&down_req, ldb, ac,
751 if (ret != LDB_SUCCESS) {
755 /* go on with the call chain */
756 return ldb_next_request(module, down_req);
759 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
760 case LDB_FLAG_MOD_DELETE:
761 if (objectclass_element->num_values == 0) {
762 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
766 case LDB_FLAG_MOD_REPLACE:
767 mem_ctx = talloc_new(ac);
768 if (mem_ctx == NULL) {
769 return LDB_ERR_OPERATIONS_ERROR;
772 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
774 talloc_free(mem_ctx);
775 return LDB_ERR_OPERATIONS_ERROR;
778 ret = fix_check_attributes(ldb, schema, msg, req->operation);
779 if (ret != LDB_SUCCESS) {
780 talloc_free(mem_ctx);
784 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
785 if (ret != LDB_SUCCESS) {
786 talloc_free(mem_ctx);
790 /* We must completely replace the existing objectClass entry,
791 * because we need it sorted */
793 ldb_msg_remove_attr(msg, "objectClass");
794 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
796 if (ret != LDB_SUCCESS) {
797 talloc_free(mem_ctx);
801 /* Move from the linked list back into an ldb msg */
802 for (current = sorted; current; current = current->next) {
803 /* copy the value as this string is on the schema
804 * context and we can't rely on it not changing
805 * before the operation is over */
806 value = talloc_strdup(msg,
807 current->objectclass->lDAPDisplayName);
810 talloc_free(mem_ctx);
811 return LDB_ERR_OPERATIONS_ERROR;
813 ret = ldb_msg_add_string(msg, "objectClass", value);
814 if (ret != LDB_SUCCESS) {
815 ldb_set_errstring(ldb,
816 "objectclass: could not re-add sorted "
817 "objectclass to modify msg");
818 talloc_free(mem_ctx);
823 talloc_free(mem_ctx);
825 ret = ldb_msg_sanity_check(ldb, msg);
826 if (ret != LDB_SUCCESS) {
830 ret = ldb_build_mod_req(&down_req, ldb, ac,
835 if (ret != LDB_SUCCESS) {
839 /* go on with the call chain */
840 return ldb_next_request(module, down_req);
843 /* This isn't the default branch of the switch, but a 'in any
844 * other case'. When a delete isn't for all objectClasses for
848 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
851 return LDB_ERR_OPERATIONS_ERROR;
854 ret = fix_check_attributes(ldb, schema, msg, req->operation);
855 if (ret != LDB_SUCCESS) {
860 ret = ldb_build_mod_req(&down_req, ldb, ac,
863 ac, oc_modify_callback,
865 if (ret != LDB_SUCCESS) {
869 return ldb_next_request(module, down_req);
872 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
874 struct ldb_context *ldb;
875 static const char * const attrs[] = { "objectClass", NULL };
876 struct ldb_request *search_req;
877 struct oc_context *ac;
880 ac = talloc_get_type(req->context, struct oc_context);
881 ldb = ldb_module_get_ctx(ac->module);
884 return ldb_module_done(ac->req, NULL, NULL,
885 LDB_ERR_OPERATIONS_ERROR);
887 if (ares->error != LDB_SUCCESS) {
888 return ldb_module_done(ac->req, ares->controls,
889 ares->response, ares->error);
892 if (ares->type != LDB_REPLY_DONE) {
894 return ldb_module_done(ac->req, NULL, NULL,
895 LDB_ERR_OPERATIONS_ERROR);
900 ret = ldb_build_search_req(&search_req, ldb, ac,
901 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
904 ac, get_search_callback,
906 if (ret != LDB_SUCCESS) {
907 return ldb_module_done(ac->req, NULL, NULL, ret);
910 ac->step_fn = objectclass_do_mod;
912 ret = ldb_next_request(ac->module, search_req);
913 if (ret != LDB_SUCCESS) {
914 return ldb_module_done(ac->req, NULL, NULL, ret);
919 static int objectclass_do_mod(struct oc_context *ac)
921 struct ldb_context *ldb;
922 const struct dsdb_schema *schema;
923 struct ldb_request *mod_req;
925 struct ldb_message_element *objectclass_element;
926 struct ldb_message *msg;
928 struct class_list *sorted, *current;
931 ldb = ldb_module_get_ctx(ac->module);
933 if (ac->search_res == NULL) {
934 return LDB_ERR_OPERATIONS_ERROR;
936 schema = dsdb_get_schema(ldb);
938 mem_ctx = talloc_new(ac);
939 if (mem_ctx == NULL) {
940 return LDB_ERR_OPERATIONS_ERROR;
943 /* use a new message structure */
944 msg = ldb_msg_new(ac);
946 ldb_set_errstring(ldb,
947 "objectclass: could not create new modify msg");
948 talloc_free(mem_ctx);
949 return LDB_ERR_OPERATIONS_ERROR;
952 /* This is now the objectClass list from the database */
953 objectclass_element = ldb_msg_find_element(ac->search_res->message,
955 if (!objectclass_element) {
956 /* Where did it go? bail now... */
957 talloc_free(mem_ctx);
958 return LDB_ERR_OPERATIONS_ERROR;
962 msg->dn = ac->req->op.mod.message->dn;
964 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
965 if (ret != LDB_SUCCESS) {
969 /* We must completely replace the existing objectClass entry.
970 * We could do a constrained add/del, but we are meant to be
971 * in a transaction... */
973 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
974 if (ret != LDB_SUCCESS) {
975 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
976 talloc_free(mem_ctx);
980 /* Move from the linked list back into an ldb msg */
981 for (current = sorted; current; current = current->next) {
982 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
985 return LDB_ERR_OPERATIONS_ERROR;
987 ret = ldb_msg_add_string(msg, "objectClass", value);
988 if (ret != LDB_SUCCESS) {
989 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
990 talloc_free(mem_ctx);
995 ret = ldb_msg_sanity_check(ldb, msg);
996 if (ret != LDB_SUCCESS) {
997 talloc_free(mem_ctx);
1001 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1006 if (ret != LDB_SUCCESS) {
1007 talloc_free(mem_ctx);
1011 talloc_free(mem_ctx);
1012 /* perform the modify */
1013 return ldb_next_request(ac->module, mod_req);
1016 static int objectclass_do_rename(struct oc_context *ac);
1018 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1020 static const char * const attrs[] = { NULL };
1021 struct ldb_context *ldb;
1022 struct ldb_request *search_req;
1023 struct oc_context *ac;
1024 struct ldb_dn *parent_dn;
1027 ldb = ldb_module_get_ctx(module);
1029 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1031 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1032 return ldb_next_request(module, req);
1035 /* Firstly ensure we are not trying to rename it to be a child of itself */
1036 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1037 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1038 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1039 ldb_dn_get_linearized(req->op.rename.olddn));
1040 return LDB_ERR_UNWILLING_TO_PERFORM;
1043 ac = oc_init_context(module, req);
1045 return LDB_ERR_OPERATIONS_ERROR;
1048 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1049 if (parent_dn == NULL) {
1051 return LDB_ERR_OPERATIONS_ERROR;
1055 it makes a search request, looking for the parent DN to fix up the new DN
1056 to a standard one, at objectclass_do_rename()
1058 ret = ldb_build_search_req(&search_req, ldb,
1059 ac, parent_dn, LDB_SCOPE_BASE,
1062 ac, get_search_callback,
1064 if (ret != LDB_SUCCESS) {
1068 /* we have to add the show deleted control, as otherwise DRS
1069 deletes will be refused as we will think the target parent
1071 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1073 if (ret != LDB_SUCCESS) {
1077 ac->step_fn = objectclass_do_rename;
1079 return ldb_next_request(ac->module, search_req);
1084 static int objectclass_do_rename(struct oc_context *ac)
1086 struct ldb_context *ldb;
1087 struct ldb_request *rename_req;
1088 struct ldb_dn *fixed_dn;
1091 ldb = ldb_module_get_ctx(ac->module);
1093 /* Check we have a valid parent */
1094 if (ac->search_res == NULL) {
1095 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1096 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1097 return LDB_ERR_UNWILLING_TO_PERFORM;
1100 /* Fix up the DN to be in the standard form,
1101 * taking particular care to match the parent DN */
1103 ac->req->op.rename.newdn,
1104 ac->search_res->message->dn,
1106 if (ret != LDB_SUCCESS) {
1110 /* TODO: Check this is a valid child to this parent,
1111 * by reading the allowedChildClasses and
1112 * allowedChildClasssesEffective attributes */
1114 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1115 ac->req->op.rename.olddn, fixed_dn,
1119 if (ret != LDB_SUCCESS) {
1123 /* perform the rename */
1124 return ldb_next_request(ac->module, rename_req);
1127 static int objectclass_init(struct ldb_module *module)
1129 struct ldb_context *ldb = ldb_module_get_ctx(module);
1131 /* Init everything else */
1132 ret = ldb_next_init(module);
1133 if (ret != LDB_SUCCESS) {
1137 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1138 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1143 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1144 .name = "objectclass",
1145 .add = objectclass_add,
1146 .modify = objectclass_modify,
1147 .rename = objectclass_rename,
1148 .init_context = objectclass_init