4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Component: objectClass sorting module
27 * - sort the objectClass attribute into the class
29 * - fix DNs and attributes into 'standard' case
30 * - Add objectCategory and ntSecurityDescriptor defaults
32 * Author: Andrew Bartlett
37 #include "ldb_module.h"
38 #include "dlinklist.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "librpc/ndr/libndr.h"
41 #include "librpc/gen_ndr/ndr_security.h"
42 #include "libcli/security/security.h"
43 #include "auth/auth.h"
44 #include "param/param.h"
45 #include "../libds/common/flags.h"
50 struct ldb_module *module;
51 struct ldb_request *req;
53 struct ldb_reply *search_res;
55 int (*step_fn)(struct oc_context *);
59 struct class_list *prev, *next;
60 const struct dsdb_class *objectclass;
63 static struct oc_context *oc_init_context(struct ldb_module *module,
64 struct ldb_request *req)
66 struct ldb_context *ldb;
67 struct oc_context *ac;
69 ldb = ldb_module_get_ctx(module);
71 ac = talloc_zero(req, struct oc_context);
73 ldb_set_errstring(ldb, "Out of Memory");
83 static int objectclass_do_add(struct oc_context *ac);
85 /* Sort objectClasses into correct order, and validate that all
86 * objectClasses specified actually exist in the schema
89 static int objectclass_sort(struct ldb_module *module,
90 const struct dsdb_schema *schema,
92 struct ldb_message_element *objectclass_element,
93 struct class_list **sorted_out)
95 struct ldb_context *ldb;
96 unsigned int i, lowest;
97 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
99 ldb = ldb_module_get_ctx(module);
103 * We work on 4 different 'bins' (implemented here as linked lists):
105 * * sorted: the eventual list, in the order we wish to push
106 * into the database. This is the only ordered list.
108 * * parent_class: The current parent class 'bin' we are
109 * trying to find subclasses for
111 * * subclass: The subclasses we have found so far
113 * * unsorted: The remaining objectClasses
115 * The process is a matter of filtering objectClasses up from
116 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
118 * We start with 'top' (found and promoted to parent_class
119 * initially). Then we find (in unsorted) all the direct
120 * subclasses of 'top'. parent_classes is concatenated onto
121 * the end of 'sorted', and subclass becomes the list in
124 * We then repeat, until we find no more subclasses. Any left
125 * over classes are added to the end.
129 /* Firstly, dump all the objectClass elements into the
130 * unsorted bin, except for 'top', which is special */
131 for (i=0; i < objectclass_element->num_values; i++) {
132 current = talloc(mem_ctx, struct class_list);
135 return LDB_ERR_OPERATIONS_ERROR;
137 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
138 if (!current->objectclass) {
139 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
140 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
141 /* This looks weird, but windows apparently returns this for invalid objectClass values */
142 return LDB_ERR_NO_SUCH_ATTRIBUTE;
143 } else if (current->objectclass->isDefunct) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
145 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146 /* This looks weird, but windows apparently returns this for invalid objectClass values */
147 return LDB_ERR_NO_SUCH_ATTRIBUTE;
150 /* Don't add top to list, we will do that later */
151 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
152 DLIST_ADD_END(unsorted, current, struct class_list *);
156 /* Add top here, to prevent duplicates */
157 current = talloc(mem_ctx, struct class_list);
158 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
159 DLIST_ADD_END(sorted, current, struct class_list *);
162 /* For each object: find parent chain */
163 for (current = unsorted; schema && current; current = current->next) {
164 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
165 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
169 /* If we didn't get to the end of the list, we need to add this parent */
170 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
174 new_parent = talloc(mem_ctx, struct class_list);
175 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
176 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
182 current_lowest = NULL;
183 for (current = unsorted; schema && current; current = current->next) {
184 if(current->objectclass->subClass_order < lowest) {
185 current_lowest = current;
186 lowest = current->objectclass->subClass_order;
190 if(current_lowest != NULL) {
191 DLIST_REMOVE(unsorted,current_lowest);
192 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
198 *sorted_out = sorted;
203 /* If we don't have schema yet, then just merge the lists again */
204 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
205 *sorted_out = sorted;
209 /* This shouldn't happen, and would break MMC, perhaps there
210 * was no 'top', a conflict in the objectClasses or some other
213 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
214 return LDB_ERR_OBJECT_CLASS_VIOLATION;
217 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
219 struct ldb_context *ldb;
220 struct oc_context *ac;
223 ac = talloc_get_type(req->context, struct oc_context);
224 ldb = ldb_module_get_ctx(ac->module);
227 return ldb_module_done(ac->req, NULL, NULL,
228 LDB_ERR_OPERATIONS_ERROR);
230 if (ares->error != LDB_SUCCESS &&
231 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
232 return ldb_module_done(ac->req, ares->controls,
233 ares->response, ares->error);
236 ldb_reset_err_string(ldb);
238 switch (ares->type) {
239 case LDB_REPLY_ENTRY:
240 if (ac->search_res != NULL) {
241 ldb_set_errstring(ldb, "Too many results");
243 return ldb_module_done(ac->req, NULL, NULL,
244 LDB_ERR_OPERATIONS_ERROR);
247 ac->search_res = talloc_steal(ac, ares);
250 case LDB_REPLY_REFERRAL:
257 ret = ac->step_fn(ac);
258 if (ret != LDB_SUCCESS) {
259 return ldb_module_done(ac->req, NULL, NULL, ret);
267 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
269 struct oc_context *ac;
271 ac = talloc_get_type(req->context, struct oc_context);
274 return ldb_module_done(ac->req, NULL, NULL,
275 LDB_ERR_OPERATIONS_ERROR);
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) {
367 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
369 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
371 return LDB_ERR_CONSTRAINT_VIOLATION;
382 * return true if msg carries an attributeSchema that is intended to be RODC
383 * filtered but is also a system-critical attribute.
385 static bool check_rodc_critical_attribute(struct ldb_message *msg)
387 uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
389 schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
390 searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
391 rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE | SEARCH_FLAG_CONFIDENTIAL);
393 if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
394 ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
402 static int objectclass_do_add(struct oc_context *ac);
404 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
406 struct ldb_context *ldb;
407 struct ldb_request *search_req;
408 struct oc_context *ac;
409 struct ldb_dn *parent_dn;
411 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
413 ldb = ldb_module_get_ctx(module);
415 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
417 /* do not manipulate our control entries */
418 if (ldb_dn_is_special(req->op.add.message->dn)) {
419 return ldb_next_request(module, req);
422 /* the objectClass must be specified on add */
423 if (ldb_msg_find_element(req->op.add.message,
424 "objectClass") == NULL) {
425 return LDB_ERR_OBJECT_CLASS_VIOLATION;
428 /* do not allow to mark an attributeSchema as RODC filtered if it
429 * is system-critical */
430 if (check_rodc_critical_attribute(req->op.add.message)) {
431 return LDB_ERR_UNWILLING_TO_PERFORM;
434 ac = oc_init_context(module, req);
436 return LDB_ERR_OPERATIONS_ERROR;
439 /* If there isn't a parent, just go on to the add processing */
440 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
441 return objectclass_do_add(ac);
444 /* get copy of parent DN */
445 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
446 if (parent_dn == NULL) {
448 return LDB_ERR_OPERATIONS_ERROR;
451 ret = ldb_build_search_req(&search_req, ldb,
452 ac, parent_dn, LDB_SCOPE_BASE,
453 "(objectClass=*)", parent_attrs,
455 ac, get_search_callback,
457 if (ret != LDB_SUCCESS) {
460 talloc_steal(search_req, parent_dn);
462 ac->step_fn = objectclass_do_add;
464 return ldb_next_request(ac->module, search_req);
467 static int objectclass_do_add(struct oc_context *ac)
469 struct ldb_context *ldb;
470 const struct dsdb_schema *schema;
471 struct ldb_request *add_req;
473 struct ldb_message_element *objectclass_element, *el;
474 struct ldb_message *msg;
476 struct class_list *sorted, *current;
478 const struct dsdb_class *objectclass;
479 int32_t systemFlags = 0;
480 const char *rdn_name = NULL;
482 ldb = ldb_module_get_ctx(ac->module);
483 schema = dsdb_get_schema(ldb, ac);
485 mem_ctx = talloc_new(ac);
486 if (mem_ctx == NULL) {
488 return LDB_ERR_OPERATIONS_ERROR;
491 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
493 /* Check we have a valid parent */
494 if (ac->search_res == NULL) {
495 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
496 /* Allow the tree to be started */
498 /* but don't keep any error string, it's meaningless */
499 ldb_set_errstring(ldb, NULL);
501 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
502 ldb_dn_get_linearized(msg->dn));
503 talloc_free(mem_ctx);
504 return LDB_ERR_NO_SUCH_OBJECT;
508 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
510 ac->req->op.add.message->dn,
511 ac->search_res->message->dn,
514 if (ret != LDB_SUCCESS) {
515 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
516 ldb_dn_get_linearized(ac->req->op.add.message->dn));
517 talloc_free(mem_ctx);
523 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
524 if (ret != LDB_SUCCESS) {
525 talloc_free(mem_ctx);
529 /* This is now the objectClass list from the database */
530 objectclass_element = ldb_msg_find_element(msg, "objectClass");
532 if (!objectclass_element) {
533 /* Where did it go? bail now... */
534 talloc_free(mem_ctx);
535 return LDB_ERR_OPERATIONS_ERROR;
537 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
538 if (ret != LDB_SUCCESS) {
539 talloc_free(mem_ctx);
543 ldb_msg_remove_attr(msg, "objectClass");
544 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
546 if (ret != LDB_SUCCESS) {
547 talloc_free(mem_ctx);
551 /* We must completely replace the existing objectClass entry,
552 * because we need it sorted */
554 /* Move from the linked list back into an ldb msg */
555 for (current = sorted; current; current = current->next) {
556 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
559 talloc_free(mem_ctx);
560 return LDB_ERR_OPERATIONS_ERROR;
562 ret = ldb_msg_add_string(msg, "objectClass", value);
563 if (ret != LDB_SUCCESS) {
564 ldb_set_errstring(ldb,
565 "objectclass: could not re-add sorted "
566 "objectclass to modify msg");
567 talloc_free(mem_ctx);
572 /* Retrive the message again so get_last_structural_class works */
573 objectclass_element = ldb_msg_find_element(msg, "objectClass");
575 /* Make sure its valid to add an object of this type */
576 objectclass = get_last_structural_class(schema,objectclass_element);
577 if(objectclass == NULL) {
578 ldb_asprintf_errstring(ldb,
579 "Failed to find a structural class for %s",
580 ldb_dn_get_linearized(msg->dn));
581 return LDB_ERR_NAMING_VIOLATION;
584 rdn_name = ldb_dn_get_rdn_name(msg->dn);
585 if (objectclass->rDNAttID
586 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
587 ldb_asprintf_errstring(ldb,
588 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
589 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
590 return LDB_ERR_NAMING_VIOLATION;
593 if (ac->search_res && ac->search_res->message) {
594 struct ldb_message_element *oc_el
595 = ldb_msg_find_element(ac->search_res->message, "objectClass");
597 bool allowed_class = false;
599 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
600 const struct dsdb_class *sclass;
602 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
604 /* We don't know this class? what is going on? */
607 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
608 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
609 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
610 allowed_class = true;
615 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
616 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
617 allowed_class = true;
624 if (!allowed_class) {
625 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
626 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
627 return LDB_ERR_NAMING_VIOLATION;
631 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
632 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
633 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
634 return LDB_ERR_UNWILLING_TO_PERFORM;
637 if (!ldb_msg_find_element(msg, "objectCategory")) {
638 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
639 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
640 /* Strip off extended components */
641 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
642 value = ldb_dn_alloc_linearized(msg, dn);
645 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
649 talloc_free(mem_ctx);
650 return LDB_ERR_OPERATIONS_ERROR;
652 ldb_msg_add_string(msg, "objectCategory", value);
654 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
655 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
659 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
660 el = ldb_msg_find_element(msg, "systemFlags");
662 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
665 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
666 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
667 ldb_msg_remove_element(msg, el);
670 /* This flag is only allowed on attributeSchema objects */
671 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
672 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
675 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
676 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
677 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
678 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
679 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
680 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
682 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
683 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
684 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
685 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
688 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
690 if (el || systemFlags != 0) {
691 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
695 talloc_free(mem_ctx);
696 ret = ldb_msg_sanity_check(ldb, msg);
699 if (ret != LDB_SUCCESS) {
703 ret = ldb_build_add_req(&add_req, ldb, ac,
708 if (ret != LDB_SUCCESS) {
712 /* perform the add */
713 return ldb_next_request(ac->module, add_req);
716 static int oc_modify_callback(struct ldb_request *req,
717 struct ldb_reply *ares);
718 static int objectclass_do_mod(struct oc_context *ac);
720 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
722 struct ldb_context *ldb = ldb_module_get_ctx(module);
723 struct ldb_message_element *objectclass_element;
724 struct ldb_message *msg;
725 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
726 struct class_list *sorted, *current;
727 struct ldb_request *down_req;
728 struct oc_context *ac;
733 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
735 /* do not manipulate our control entries */
736 if (ldb_dn_is_special(req->op.mod.message->dn)) {
737 return ldb_next_request(module, req);
740 /* Without schema, there isn't much to do here */
742 return ldb_next_request(module, req);
745 /* As with the "real" AD we don't accept empty messages */
746 if (req->op.mod.message->num_elements == 0) {
747 ldb_set_errstring(ldb, "objectclass: modify message must have "
748 "elements/attributes!");
749 return LDB_ERR_UNWILLING_TO_PERFORM;
752 /* do not allow to mark an attributeSchema as RODC filtered if it
753 * is system-critical */
754 if (check_rodc_critical_attribute(req->op.mod.message)) {
755 return LDB_ERR_UNWILLING_TO_PERFORM;
758 ac = oc_init_context(module, req);
761 return LDB_ERR_OPERATIONS_ERROR;
764 if (!talloc_reference(ac, schema)) {
766 return LDB_ERR_OPERATIONS_ERROR;
769 /* If no part of this touches the objectClass, then we don't
770 * need to make any changes. */
771 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
773 /* If the only operation is the deletion of the objectClass
774 * then go on with just fixing the attribute case */
775 if (!objectclass_element) {
776 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
778 return LDB_ERR_OPERATIONS_ERROR;
781 ret = fix_check_attributes(ldb, schema, msg, req->operation);
782 if (ret != LDB_SUCCESS) {
786 ret = ldb_build_mod_req(&down_req, ldb, ac,
791 if (ret != LDB_SUCCESS) {
795 /* go on with the call chain */
796 return ldb_next_request(module, down_req);
799 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
800 case LDB_FLAG_MOD_DELETE:
801 if (objectclass_element->num_values == 0) {
802 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
806 case LDB_FLAG_MOD_REPLACE:
807 mem_ctx = talloc_new(ac);
808 if (mem_ctx == NULL) {
809 return LDB_ERR_OPERATIONS_ERROR;
812 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
814 talloc_free(mem_ctx);
815 return LDB_ERR_OPERATIONS_ERROR;
818 ret = fix_check_attributes(ldb, schema, msg, req->operation);
819 if (ret != LDB_SUCCESS) {
820 talloc_free(mem_ctx);
824 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
825 if (ret != LDB_SUCCESS) {
826 talloc_free(mem_ctx);
830 /* We must completely replace the existing objectClass entry,
831 * because we need it sorted */
833 ldb_msg_remove_attr(msg, "objectClass");
834 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
836 if (ret != LDB_SUCCESS) {
837 talloc_free(mem_ctx);
841 /* Move from the linked list back into an ldb msg */
842 for (current = sorted; current; current = current->next) {
843 /* copy the value as this string is on the schema
844 * context and we can't rely on it not changing
845 * before the operation is over */
846 value = talloc_strdup(msg,
847 current->objectclass->lDAPDisplayName);
850 talloc_free(mem_ctx);
851 return LDB_ERR_OPERATIONS_ERROR;
853 ret = ldb_msg_add_string(msg, "objectClass", value);
854 if (ret != LDB_SUCCESS) {
855 ldb_set_errstring(ldb,
856 "objectclass: could not re-add sorted "
857 "objectclass to modify msg");
858 talloc_free(mem_ctx);
863 talloc_free(mem_ctx);
865 ret = ldb_msg_sanity_check(ldb, msg);
866 if (ret != LDB_SUCCESS) {
870 ret = ldb_build_mod_req(&down_req, ldb, ac,
875 if (ret != LDB_SUCCESS) {
879 /* go on with the call chain */
880 return ldb_next_request(module, down_req);
883 /* This isn't the default branch of the switch, but a 'in any
884 * other case'. When a delete isn't for all objectClasses for
888 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
891 return LDB_ERR_OPERATIONS_ERROR;
894 ret = fix_check_attributes(ldb, schema, msg, req->operation);
895 if (ret != LDB_SUCCESS) {
900 ret = ldb_build_mod_req(&down_req, ldb, ac,
903 ac, oc_modify_callback,
905 if (ret != LDB_SUCCESS) {
909 return ldb_next_request(module, down_req);
912 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
914 struct ldb_context *ldb;
915 static const char * const attrs[] = { "objectClass", NULL };
916 struct ldb_request *search_req;
917 struct oc_context *ac;
920 ac = talloc_get_type(req->context, struct oc_context);
921 ldb = ldb_module_get_ctx(ac->module);
924 return ldb_module_done(ac->req, NULL, NULL,
925 LDB_ERR_OPERATIONS_ERROR);
927 if (ares->error != LDB_SUCCESS) {
928 return ldb_module_done(ac->req, ares->controls,
929 ares->response, ares->error);
932 if (ares->type != LDB_REPLY_DONE) {
934 return ldb_module_done(ac->req, NULL, NULL,
935 LDB_ERR_OPERATIONS_ERROR);
940 ret = ldb_build_search_req(&search_req, ldb, ac,
941 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
944 ac, get_search_callback,
946 if (ret != LDB_SUCCESS) {
947 return ldb_module_done(ac->req, NULL, NULL, ret);
950 ac->step_fn = objectclass_do_mod;
952 ret = ldb_next_request(ac->module, search_req);
953 if (ret != LDB_SUCCESS) {
954 return ldb_module_done(ac->req, NULL, NULL, ret);
959 static int objectclass_do_mod(struct oc_context *ac)
961 struct ldb_context *ldb;
962 const struct dsdb_schema *schema;
963 struct ldb_request *mod_req;
965 struct ldb_message_element *objectclass_element;
966 struct ldb_message *msg;
968 struct class_list *sorted, *current;
971 ldb = ldb_module_get_ctx(ac->module);
973 if (ac->search_res == NULL) {
974 return LDB_ERR_OPERATIONS_ERROR;
976 schema = dsdb_get_schema(ldb, ac);
978 mem_ctx = talloc_new(ac);
979 if (mem_ctx == NULL) {
980 return LDB_ERR_OPERATIONS_ERROR;
983 /* use a new message structure */
984 msg = ldb_msg_new(ac);
986 ldb_set_errstring(ldb,
987 "objectclass: could not create new modify msg");
988 talloc_free(mem_ctx);
989 return LDB_ERR_OPERATIONS_ERROR;
992 /* This is now the objectClass list from the database */
993 objectclass_element = ldb_msg_find_element(ac->search_res->message,
995 if (!objectclass_element) {
996 /* Where did it go? bail now... */
997 talloc_free(mem_ctx);
998 return LDB_ERR_OPERATIONS_ERROR;
1002 msg->dn = ac->req->op.mod.message->dn;
1004 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
1005 if (ret != LDB_SUCCESS) {
1009 /* We must completely replace the existing objectClass entry.
1010 * We could do a constrained add/del, but we are meant to be
1011 * in a transaction... */
1013 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
1014 if (ret != LDB_SUCCESS) {
1015 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
1016 talloc_free(mem_ctx);
1020 /* Move from the linked list back into an ldb msg */
1021 for (current = sorted; current; current = current->next) {
1022 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
1023 if (value == NULL) {
1025 return LDB_ERR_OPERATIONS_ERROR;
1027 ret = ldb_msg_add_string(msg, "objectClass", value);
1028 if (ret != LDB_SUCCESS) {
1029 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1030 talloc_free(mem_ctx);
1035 ret = ldb_msg_sanity_check(ldb, msg);
1036 if (ret != LDB_SUCCESS) {
1037 talloc_free(mem_ctx);
1041 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1046 if (ret != LDB_SUCCESS) {
1047 talloc_free(mem_ctx);
1051 talloc_free(mem_ctx);
1052 /* perform the modify */
1053 return ldb_next_request(ac->module, mod_req);
1056 static int objectclass_do_rename(struct oc_context *ac);
1058 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1060 static const char * const attrs[] = { NULL };
1061 struct ldb_context *ldb;
1062 struct ldb_request *search_req;
1063 struct oc_context *ac;
1064 struct ldb_dn *parent_dn;
1067 ldb = ldb_module_get_ctx(module);
1069 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1071 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1072 return ldb_next_request(module, req);
1075 /* Firstly ensure we are not trying to rename it to be a child of itself */
1076 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1077 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1078 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1079 ldb_dn_get_linearized(req->op.rename.olddn));
1080 return LDB_ERR_UNWILLING_TO_PERFORM;
1083 ac = oc_init_context(module, req);
1085 return LDB_ERR_OPERATIONS_ERROR;
1088 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1089 if (parent_dn == NULL) {
1091 return LDB_ERR_OPERATIONS_ERROR;
1095 it makes a search request, looking for the parent DN to fix up the new DN
1096 to a standard one, at objectclass_do_rename()
1098 ret = ldb_build_search_req(&search_req, ldb,
1099 ac, parent_dn, LDB_SCOPE_BASE,
1102 ac, get_search_callback,
1104 if (ret != LDB_SUCCESS) {
1108 /* we have to add the show deleted control, as otherwise DRS
1109 deletes will be refused as we will think the target parent
1111 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1113 if (ret != LDB_SUCCESS) {
1117 ac->step_fn = objectclass_do_rename;
1119 return ldb_next_request(ac->module, search_req);
1124 static int objectclass_do_rename(struct oc_context *ac)
1126 struct ldb_context *ldb;
1127 struct ldb_request *rename_req;
1128 struct ldb_dn *fixed_dn;
1131 ldb = ldb_module_get_ctx(ac->module);
1133 /* Check we have a valid parent */
1134 if (ac->search_res == NULL) {
1135 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1136 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1137 return LDB_ERR_UNWILLING_TO_PERFORM;
1140 /* Fix up the DN to be in the standard form,
1141 * taking particular care to match the parent DN */
1143 ac->req->op.rename.newdn,
1144 ac->search_res->message->dn,
1146 if (ret != LDB_SUCCESS) {
1150 /* TODO: Check this is a valid child to this parent,
1151 * by reading the allowedChildClasses and
1152 * allowedChildClasssesEffective attributes */
1154 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1155 ac->req->op.rename.olddn, fixed_dn,
1159 if (ret != LDB_SUCCESS) {
1163 /* perform the rename */
1164 return ldb_next_request(ac->module, rename_req);
1167 static int objectclass_init(struct ldb_module *module)
1169 struct ldb_context *ldb = ldb_module_get_ctx(module);
1171 /* Init everything else */
1172 ret = ldb_next_init(module);
1173 if (ret != LDB_SUCCESS) {
1177 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1178 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1183 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1184 .name = "objectclass",
1185 .add = objectclass_add,
1186 .modify = objectclass_modify,
1187 .rename = objectclass_rename,
1188 .init_context = objectclass_init