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"
49 struct ldb_module *module;
50 struct ldb_request *req;
52 struct ldb_reply *search_res;
54 int (*step_fn)(struct oc_context *);
58 struct class_list *prev, *next;
59 const struct dsdb_class *objectclass;
62 static struct oc_context *oc_init_context(struct ldb_module *module,
63 struct ldb_request *req)
65 struct ldb_context *ldb;
66 struct oc_context *ac;
68 ldb = ldb_module_get_ctx(module);
70 ac = talloc_zero(req, struct oc_context);
72 ldb_set_errstring(ldb, "Out of Memory");
82 static int objectclass_do_add(struct oc_context *ac);
84 /* Sort objectClasses into correct order, and validate that all
85 * objectClasses specified actually exist in the schema
88 static int objectclass_sort(struct ldb_module *module,
89 const struct dsdb_schema *schema,
91 struct ldb_message_element *objectclass_element,
92 struct class_list **sorted_out)
94 struct ldb_context *ldb;
97 struct class_list *sorted = NULL, *parent_class = NULL,
98 *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent;
100 ldb = ldb_module_get_ctx(module);
104 * We work on 4 different 'bins' (implemented here as linked lists):
106 * * sorted: the eventual list, in the order we wish to push
107 * into the database. This is the only ordered list.
109 * * parent_class: The current parent class 'bin' we are
110 * trying to find subclasses for
112 * * subclass: The subclasses we have found so far
114 * * unsorted: The remaining objectClasses
116 * The process is a matter of filtering objectClasses up from
117 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
119 * We start with 'top' (found and promoted to parent_class
120 * initially). Then we find (in unsorted) all the direct
121 * subclasses of 'top'. parent_classes is concatenated onto
122 * the end of 'sorted', and subclass becomes the list in
125 * We then repeat, until we find no more subclasses. Any left
126 * over classes are added to the end.
130 /* Firstly, dump all the objectClass elements into the
131 * unsorted bin, except for 'top', which is special */
132 for (i=0; i < objectclass_element->num_values; i++) {
133 current = talloc(mem_ctx, struct class_list);
136 return LDB_ERR_OPERATIONS_ERROR;
138 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
139 if (!current->objectclass) {
140 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
141 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
142 /* This looks weird, but windows apparently returns this for invalid objectClass values */
143 return LDB_ERR_NO_SUCH_ATTRIBUTE;
144 } else if (current->objectclass->isDefunct) {
145 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
146 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
147 /* This looks weird, but windows apparently returns this for invalid objectClass values */
148 return LDB_ERR_NO_SUCH_ATTRIBUTE;
151 /* this is the root of the tree. We will start
152 * looking for subclasses from here */
153 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) {
154 DLIST_ADD_END(parent_class, current, struct class_list *);
156 DLIST_ADD_END(unsorted, current, struct class_list *);
160 if (parent_class == NULL) {
161 current = talloc(mem_ctx, struct class_list);
162 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
163 DLIST_ADD_END(parent_class, current, struct class_list *);
166 /* For each object: find parent chain */
167 for (current = unsorted; schema && current; current = current->next) {
168 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
169 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
173 /* If we didn't get to the end of the list, we need to add this parent */
174 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
178 new_parent = talloc(mem_ctx, struct class_list);
179 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
180 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
183 /* DEBUGGING aid: how many layers are we down now? */
187 /* Find all the subclasses of classes in the
188 * parent_classes. Push them onto the subclass list */
190 /* Ensure we don't bother if there are no unsorted entries left */
191 for (current = parent_class; schema && unsorted && current; current = current->next) {
192 /* Walk the list of possible subclasses in unsorted */
193 for (poss_subclass = unsorted; poss_subclass; ) {
194 struct class_list *next;
196 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
197 next = poss_subclass->next;
199 if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) {
200 DLIST_REMOVE(unsorted, poss_subclass);
201 DLIST_ADD(subclass, poss_subclass);
205 poss_subclass = next;
209 /* Now push the parent_classes as sorted, we are done with
210 these. Add to the END of the list by concatenation */
211 DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
213 /* and now find subclasses of these */
214 parent_class = subclass;
217 /* If we didn't find any subclasses we will fall out
219 } while (parent_class);
222 *sorted_out = sorted;
227 /* If we don't have schema yet, then just merge the lists again */
228 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
229 *sorted_out = sorted;
233 /* This shouldn't happen, and would break MMC, perhaps there
234 * was no 'top', a conflict in the objectClasses or some other
237 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
238 return LDB_ERR_OBJECT_CLASS_VIOLATION;
241 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
243 struct ldb_context *ldb;
244 struct oc_context *ac;
247 ac = talloc_get_type(req->context, struct oc_context);
248 ldb = ldb_module_get_ctx(ac->module);
251 return ldb_module_done(ac->req, NULL, NULL,
252 LDB_ERR_OPERATIONS_ERROR);
254 if (ares->error != LDB_SUCCESS &&
255 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
256 return ldb_module_done(ac->req, ares->controls,
257 ares->response, ares->error);
260 ldb_reset_err_string(ldb);
262 switch (ares->type) {
263 case LDB_REPLY_ENTRY:
264 if (ac->search_res != NULL) {
265 ldb_set_errstring(ldb, "Too many results");
267 return ldb_module_done(ac->req, NULL, NULL,
268 LDB_ERR_OPERATIONS_ERROR);
271 ac->search_res = talloc_steal(ac, ares);
274 case LDB_REPLY_REFERRAL:
281 ret = ac->step_fn(ac);
282 if (ret != LDB_SUCCESS) {
283 return ldb_module_done(ac->req, NULL, NULL, ret);
291 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
293 struct oc_context *ac;
295 ac = talloc_get_type(req->context, struct oc_context);
298 return ldb_module_done(ac->req, NULL, NULL,
299 LDB_ERR_OPERATIONS_ERROR);
301 if (ares->error != LDB_SUCCESS) {
302 return ldb_module_done(ac->req, ares->controls,
303 ares->response, ares->error);
306 if (ares->type != LDB_REPLY_DONE) {
308 return ldb_module_done(ac->req, NULL, NULL,
309 LDB_ERR_OPERATIONS_ERROR);
312 return ldb_module_done(ac->req, ares->controls,
313 ares->response, ares->error);
316 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
318 This should mean that if the parent is:
319 CN=Users,DC=samba,DC=example,DC=com
320 and a proposed child is
321 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
323 The resulting DN should be:
325 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
328 static int fix_dn(TALLOC_CTX *mem_ctx,
329 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
330 struct ldb_dn **fixed_dn)
332 char *upper_rdn_attr;
333 const struct ldb_val *rdn_val;
335 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
336 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
338 /* We need the attribute name in upper case */
339 upper_rdn_attr = strupper_talloc(*fixed_dn,
340 ldb_dn_get_rdn_name(newdn));
341 if (!upper_rdn_attr) {
342 return LDB_ERR_OPERATIONS_ERROR;
345 /* Create a new child */
346 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
347 return LDB_ERR_OPERATIONS_ERROR;
351 rdn_val = ldb_dn_get_rdn_val(newdn);
354 /* the rules for rDN length constraints are more complex than
355 this. Until we understand them we need to leave this
356 constraint out. Otherwise we break replication, as windows
357 does sometimes send us rDNs longer than 64 */
358 if (!rdn_val || rdn_val->length > 64) {
359 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
364 /* And replace it with CN=foo (we need the attribute in upper case */
365 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
368 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
369 static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg)
372 for (i=0; i < msg->num_elements; i++) {
373 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
374 /* Add in a very special case for 'clearTextPassword',
375 * which is used for internal processing only, and is
376 * not presented in the schema */
378 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
379 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
380 /* Apparently Windows sends exactly this behaviour */
381 return LDB_ERR_NO_SUCH_ATTRIBUTE;
384 msg->elements[i].name = attribute->lDAPDisplayName;
391 static int objectclass_do_add(struct oc_context *ac);
393 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
395 struct ldb_context *ldb;
396 struct ldb_request *search_req;
397 struct oc_context *ac;
398 struct ldb_dn *parent_dn;
400 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
402 ldb = ldb_module_get_ctx(module);
404 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
406 /* do not manipulate our control entries */
407 if (ldb_dn_is_special(req->op.add.message->dn)) {
408 return ldb_next_request(module, req);
411 /* the objectClass must be specified on add */
412 if (ldb_msg_find_element(req->op.add.message,
413 "objectClass") == NULL) {
414 return LDB_ERR_OBJECT_CLASS_VIOLATION;
417 ac = oc_init_context(module, req);
419 return LDB_ERR_OPERATIONS_ERROR;
422 /* If there isn't a parent, just go on to the add processing */
423 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
424 return objectclass_do_add(ac);
427 /* get copy of parent DN */
428 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
429 if (parent_dn == NULL) {
431 return LDB_ERR_OPERATIONS_ERROR;
434 ret = ldb_build_search_req(&search_req, ldb,
435 ac, parent_dn, LDB_SCOPE_BASE,
436 "(objectClass=*)", parent_attrs,
438 ac, get_search_callback,
440 if (ret != LDB_SUCCESS) {
443 talloc_steal(search_req, parent_dn);
445 ac->step_fn = objectclass_do_add;
447 return ldb_next_request(ac->module, search_req);
450 static int objectclass_do_add(struct oc_context *ac)
452 struct ldb_context *ldb;
453 const struct dsdb_schema *schema;
454 struct ldb_request *add_req;
456 struct ldb_message_element *objectclass_element;
457 struct ldb_message *msg;
459 struct class_list *sorted, *current;
462 ldb = ldb_module_get_ctx(ac->module);
463 schema = dsdb_get_schema(ldb);
465 mem_ctx = talloc_new(ac);
466 if (mem_ctx == NULL) {
467 return LDB_ERR_OPERATIONS_ERROR;
470 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
472 /* Check we have a valid parent */
473 if (ac->search_res == NULL) {
474 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
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;
487 const struct ldb_val *parent_guid;
489 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
491 ac->req->op.add.message->dn,
492 ac->search_res->message->dn,
495 if (ret != LDB_SUCCESS) {
496 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
497 ldb_dn_get_linearized(ac->req->op.add.message->dn));
498 talloc_free(mem_ctx);
502 parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID");
503 if (parent_guid == NULL) {
504 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not have an objectGUID!",
505 ldb_dn_get_linearized(msg->dn));
506 talloc_free(mem_ctx);
507 return LDB_ERR_UNWILLING_TO_PERFORM;
510 ret = ldb_msg_add_steal_value(msg, "parentGUID", discard_const(parent_guid));
511 if (ret != LDB_SUCCESS) {
512 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, failed to add parentGUID",
513 ldb_dn_get_linearized(msg->dn));
514 talloc_free(mem_ctx);
515 return LDB_ERR_UNWILLING_TO_PERFORM;
519 ret = fix_attributes(ldb, schema, msg);
520 if (ret != LDB_SUCCESS) {
521 talloc_free(mem_ctx);
525 /* This is now the objectClass list from the database */
526 objectclass_element = ldb_msg_find_element(msg, "objectClass");
528 if (!objectclass_element) {
529 /* Where did it go? bail now... */
530 talloc_free(mem_ctx);
531 return LDB_ERR_OPERATIONS_ERROR;
533 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
534 if (ret != LDB_SUCCESS) {
535 talloc_free(mem_ctx);
539 ldb_msg_remove_attr(msg, "objectClass");
540 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
542 if (ret != LDB_SUCCESS) {
543 talloc_free(mem_ctx);
547 /* We must completely replace the existing objectClass entry,
548 * because we need it sorted */
550 /* Move from the linked list back into an ldb msg */
551 for (current = sorted; current; current = current->next) {
552 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
555 talloc_free(mem_ctx);
556 return LDB_ERR_OPERATIONS_ERROR;
558 ret = ldb_msg_add_string(msg, "objectClass", value);
559 if (ret != LDB_SUCCESS) {
560 ldb_set_errstring(ldb,
561 "objectclass: could not re-add sorted "
562 "objectclass to modify msg");
563 talloc_free(mem_ctx);
566 /* Last one is the critical one */
567 if (!current->next) {
568 struct ldb_message_element *el;
569 int32_t systemFlags = 0;
570 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
571 if (current->objectclass->rDNAttID
572 && ldb_attr_cmp(rdn_name, current->objectclass->rDNAttID) != 0) {
573 ldb_asprintf_errstring(ldb,
574 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
575 rdn_name, current->objectclass->lDAPDisplayName, current->objectclass->rDNAttID);
576 return LDB_ERR_NAMING_VIOLATION;
579 if (ac->search_res && ac->search_res->message) {
580 struct ldb_message_element *oc_el
581 = ldb_msg_find_element(ac->search_res->message, "objectClass");
583 bool allowed_class = false;
585 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
586 const struct dsdb_class *sclass;
588 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
590 /* We don't know this class? what is going on? */
593 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
594 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
595 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
596 allowed_class = true;
601 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
602 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
603 allowed_class = true;
610 if (!allowed_class) {
611 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
612 current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
613 return LDB_ERR_NAMING_VIOLATION;
617 if (current->objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
618 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
619 current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
620 return LDB_ERR_UNWILLING_TO_PERFORM;
623 if (!ldb_msg_find_element(msg, "objectCategory")) {
624 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
625 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
626 /* Strip off extended components */
627 struct ldb_dn *dn = ldb_dn_new(msg, ldb, current->objectclass->defaultObjectCategory);
628 value = ldb_dn_alloc_linearized(msg, dn);
631 value = talloc_strdup(msg, current->objectclass->defaultObjectCategory);
635 talloc_free(mem_ctx);
636 return LDB_ERR_OPERATIONS_ERROR;
638 ldb_msg_add_string(msg, "objectCategory", value);
640 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
641 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
645 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
646 el = ldb_msg_find_element(msg, "systemFlags");
648 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
651 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
652 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
653 ldb_msg_remove_element(msg, el);
656 /* This flag is only allowed on attributeSchema objects */
657 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) {
658 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
661 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "server") == 0) {
662 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
663 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "site") == 0
664 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "serverContainer") == 0
665 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
666 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
668 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0
669 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0
670 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
671 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
674 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
676 if (el || systemFlags != 0) {
677 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
683 talloc_free(mem_ctx);
684 ret = ldb_msg_sanity_check(ldb, msg);
687 if (ret != LDB_SUCCESS) {
691 ret = ldb_build_add_req(&add_req, ldb, ac,
696 if (ret != LDB_SUCCESS) {
700 /* perform the add */
701 return ldb_next_request(ac->module, add_req);
704 static int oc_modify_callback(struct ldb_request *req,
705 struct ldb_reply *ares);
706 static int objectclass_do_mod(struct oc_context *ac);
708 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
710 struct ldb_context *ldb = ldb_module_get_ctx(module);
711 struct ldb_message_element *objectclass_element;
712 struct ldb_message *msg;
713 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
714 struct class_list *sorted, *current;
715 struct ldb_request *down_req;
716 struct oc_context *ac;
721 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
723 /* do not manipulate our control entries */
724 if (ldb_dn_is_special(req->op.mod.message->dn)) {
725 return ldb_next_request(module, req);
728 /* Without schema, there isn't much to do here */
730 return ldb_next_request(module, req);
733 /* As with the "real" AD we don't accept empty messages */
734 if (req->op.mod.message->num_elements == 0) {
735 ldb_set_errstring(ldb, "objectclass: modify message must have "
736 "elements/attributes!");
737 return LDB_ERR_UNWILLING_TO_PERFORM;
740 ac = oc_init_context(module, req);
742 return LDB_ERR_OPERATIONS_ERROR;
745 /* If no part of this touches the objectClass, then we don't
746 * need to make any changes. */
747 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
749 /* If the only operation is the deletion of the objectClass
750 * then go on with just fixing the attribute case */
751 if (!objectclass_element) {
752 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
754 return LDB_ERR_OPERATIONS_ERROR;
757 ret = fix_attributes(ldb, schema, msg);
758 if (ret != LDB_SUCCESS) {
762 ret = ldb_build_mod_req(&down_req, ldb, ac,
767 if (ret != LDB_SUCCESS) {
771 /* go on with the call chain */
772 return ldb_next_request(module, down_req);
775 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
776 case LDB_FLAG_MOD_DELETE:
777 if (objectclass_element->num_values == 0) {
778 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
782 case LDB_FLAG_MOD_REPLACE:
783 mem_ctx = talloc_new(ac);
784 if (mem_ctx == NULL) {
785 return LDB_ERR_OPERATIONS_ERROR;
788 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
790 talloc_free(mem_ctx);
791 return LDB_ERR_OPERATIONS_ERROR;
794 ret = fix_attributes(ldb, schema, msg);
795 if (ret != LDB_SUCCESS) {
796 talloc_free(mem_ctx);
800 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
801 if (ret != LDB_SUCCESS) {
802 talloc_free(mem_ctx);
806 /* We must completely replace the existing objectClass entry,
807 * because we need it sorted */
809 ldb_msg_remove_attr(msg, "objectClass");
810 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
812 if (ret != LDB_SUCCESS) {
813 talloc_free(mem_ctx);
817 /* Move from the linked list back into an ldb msg */
818 for (current = sorted; current; current = current->next) {
819 /* copy the value as this string is on the schema
820 * context and we can't rely on it not changing
821 * before the operation is over */
822 value = talloc_strdup(msg,
823 current->objectclass->lDAPDisplayName);
826 talloc_free(mem_ctx);
827 return LDB_ERR_OPERATIONS_ERROR;
829 ret = ldb_msg_add_string(msg, "objectClass", value);
830 if (ret != LDB_SUCCESS) {
831 ldb_set_errstring(ldb,
832 "objectclass: could not re-add sorted "
833 "objectclass to modify msg");
834 talloc_free(mem_ctx);
839 talloc_free(mem_ctx);
841 ret = ldb_msg_sanity_check(ldb, msg);
842 if (ret != LDB_SUCCESS) {
846 ret = ldb_build_mod_req(&down_req, ldb, ac,
851 if (ret != LDB_SUCCESS) {
855 /* go on with the call chain */
856 return ldb_next_request(module, down_req);
859 /* This isn't the default branch of the switch, but a 'in any
860 * other case'. When a delete isn't for all objectClasses for
864 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
867 return LDB_ERR_OPERATIONS_ERROR;
870 ret = fix_attributes(ldb, schema, msg);
871 if (ret != LDB_SUCCESS) {
876 ret = ldb_build_mod_req(&down_req, ldb, ac,
879 ac, oc_modify_callback,
881 if (ret != LDB_SUCCESS) {
885 return ldb_next_request(module, down_req);
888 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
890 struct ldb_context *ldb;
891 static const char * const attrs[] = { "objectClass", NULL };
892 struct ldb_request *search_req;
893 struct oc_context *ac;
896 ac = talloc_get_type(req->context, struct oc_context);
897 ldb = ldb_module_get_ctx(ac->module);
900 return ldb_module_done(ac->req, NULL, NULL,
901 LDB_ERR_OPERATIONS_ERROR);
903 if (ares->error != LDB_SUCCESS) {
904 return ldb_module_done(ac->req, ares->controls,
905 ares->response, ares->error);
908 if (ares->type != LDB_REPLY_DONE) {
910 return ldb_module_done(ac->req, NULL, NULL,
911 LDB_ERR_OPERATIONS_ERROR);
916 ret = ldb_build_search_req(&search_req, ldb, ac,
917 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
920 ac, get_search_callback,
922 if (ret != LDB_SUCCESS) {
923 return ldb_module_done(ac->req, NULL, NULL, ret);
926 ac->step_fn = objectclass_do_mod;
928 ret = ldb_next_request(ac->module, search_req);
929 if (ret != LDB_SUCCESS) {
930 return ldb_module_done(ac->req, NULL, NULL, ret);
935 static int objectclass_do_mod(struct oc_context *ac)
937 struct ldb_context *ldb;
938 const struct dsdb_schema *schema;
939 struct ldb_request *mod_req;
941 struct ldb_message_element *objectclass_element;
942 struct ldb_message *msg;
944 struct class_list *sorted, *current;
947 ldb = ldb_module_get_ctx(ac->module);
949 if (ac->search_res == NULL) {
950 return LDB_ERR_OPERATIONS_ERROR;
952 schema = dsdb_get_schema(ldb);
954 mem_ctx = talloc_new(ac);
955 if (mem_ctx == NULL) {
956 return LDB_ERR_OPERATIONS_ERROR;
959 /* use a new message structure */
960 msg = ldb_msg_new(ac);
962 ldb_set_errstring(ldb,
963 "objectclass: could not create new modify msg");
964 talloc_free(mem_ctx);
965 return LDB_ERR_OPERATIONS_ERROR;
968 /* This is now the objectClass list from the database */
969 objectclass_element = ldb_msg_find_element(ac->search_res->message,
971 if (!objectclass_element) {
972 /* Where did it go? bail now... */
973 talloc_free(mem_ctx);
974 return LDB_ERR_OPERATIONS_ERROR;
978 msg->dn = ac->req->op.mod.message->dn;
980 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
981 if (ret != LDB_SUCCESS) {
985 /* We must completely replace the existing objectClass entry.
986 * We could do a constrained add/del, but we are meant to be
987 * in a transaction... */
989 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
990 if (ret != LDB_SUCCESS) {
991 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
992 talloc_free(mem_ctx);
996 /* Move from the linked list back into an ldb msg */
997 for (current = sorted; current; current = current->next) {
998 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
1001 return LDB_ERR_OPERATIONS_ERROR;
1003 ret = ldb_msg_add_string(msg, "objectClass", value);
1004 if (ret != LDB_SUCCESS) {
1005 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1006 talloc_free(mem_ctx);
1011 ret = ldb_msg_sanity_check(ldb, msg);
1012 if (ret != LDB_SUCCESS) {
1013 talloc_free(mem_ctx);
1017 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1022 if (ret != LDB_SUCCESS) {
1023 talloc_free(mem_ctx);
1027 talloc_free(mem_ctx);
1028 /* perform the modify */
1029 return ldb_next_request(ac->module, mod_req);
1032 static int objectclass_do_rename(struct oc_context *ac);
1034 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1036 static const char * const attrs[] = { "objectGUID", NULL };
1037 struct ldb_context *ldb;
1038 struct ldb_request *search_req;
1039 struct oc_context *ac;
1040 struct ldb_dn *parent_dn;
1043 ldb = ldb_module_get_ctx(module);
1045 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1047 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1048 return ldb_next_request(module, req);
1051 /* Firstly ensure we are not trying to rename it to be a child of itself */
1052 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1053 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1054 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1055 ldb_dn_get_linearized(req->op.rename.olddn));
1056 return LDB_ERR_UNWILLING_TO_PERFORM;
1059 ac = oc_init_context(module, req);
1061 return LDB_ERR_OPERATIONS_ERROR;
1064 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1065 if (parent_dn == NULL) {
1067 return LDB_ERR_OPERATIONS_ERROR;
1070 /* note that the results of this search are kept and used to
1071 update the parentGUID in objectclass_rename_callback() */
1072 ret = ldb_build_search_req(&search_req, ldb,
1073 ac, parent_dn, LDB_SCOPE_BASE,
1076 ac, get_search_callback,
1078 if (ret != LDB_SUCCESS) {
1082 /* we have to add the show deleted control, as otherwise DRS
1083 deletes will be refused as we will think the target parent
1085 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1087 if (ret != LDB_SUCCESS) {
1091 ac->step_fn = objectclass_do_rename;
1093 return ldb_next_request(ac->module, search_req);
1097 called after the rename happens.
1098 We now need to fix the parentGUID of the object to be the objectGUID of
1101 static int objectclass_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
1103 struct ldb_context *ldb;
1104 struct oc_context *ac;
1105 const struct ldb_val *parent_guid;
1106 struct ldb_request *mod_req = NULL;
1108 struct ldb_message *msg;
1109 struct ldb_message_element *el = NULL;
1111 ac = talloc_get_type(req->context, struct oc_context);
1112 ldb = ldb_module_get_ctx(ac->module);
1114 /* make sure the rename succeeded */
1116 return ldb_module_done(ac->req, NULL, NULL,
1117 LDB_ERR_OPERATIONS_ERROR);
1119 if (ares->error != LDB_SUCCESS) {
1120 return ldb_module_done(ac->req, ares->controls,
1121 ares->response, ares->error);
1126 /* the ac->search_res should contain the new parents objectGUID */
1127 parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID");
1128 if (parent_guid == NULL) {
1129 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, new parent does not have an objectGUID!",
1130 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1131 return LDB_ERR_UNWILLING_TO_PERFORM;
1135 /* construct the modify message */
1136 msg = ldb_msg_new(ac);
1139 return LDB_ERR_OPERATIONS_ERROR;
1142 msg->dn = ac->req->op.rename.newdn;
1144 ret = ldb_msg_add_value(msg, "parentGUID", parent_guid, &el);
1145 if (ret != LDB_SUCCESS) {
1149 el->flags = LDB_FLAG_MOD_REPLACE;
1151 ret = ldb_build_mod_req(&mod_req, ldb, ac, msg,
1152 NULL, ac, oc_op_callback, req);
1154 return ldb_next_request(ac->module, mod_req);
1157 static int objectclass_do_rename(struct oc_context *ac)
1159 struct ldb_context *ldb;
1160 struct ldb_request *rename_req;
1161 struct ldb_dn *fixed_dn;
1164 ldb = ldb_module_get_ctx(ac->module);
1166 /* Check we have a valid parent */
1167 if (ac->search_res == NULL) {
1168 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1169 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1170 return LDB_ERR_UNWILLING_TO_PERFORM;
1173 /* Fix up the DN to be in the standard form,
1174 * taking particular care to match the parent DN */
1176 ac->req->op.rename.newdn,
1177 ac->search_res->message->dn,
1179 if (ret != LDB_SUCCESS) {
1183 /* TODO: Check this is a valid child to this parent,
1184 * by reading the allowedChildClasses and
1185 * allowedChildClasssesEffective attributes */
1187 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1188 ac->req->op.rename.olddn, fixed_dn,
1190 ac, objectclass_rename_callback,
1192 if (ret != LDB_SUCCESS) {
1196 /* perform the rename */
1197 return ldb_next_request(ac->module, rename_req);
1200 static int objectclass_init(struct ldb_module *module)
1202 struct ldb_context *ldb = ldb_module_get_ctx(module);
1204 /* Init everything else */
1205 ret = ldb_next_init(module);
1206 if (ret != LDB_SUCCESS) {
1210 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1211 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1213 return ldb_next_init(module);
1216 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1217 .name = "objectclass",
1218 .add = objectclass_add,
1219 .modify = objectclass_modify,
1220 .rename = objectclass_rename,
1221 .init_context = objectclass_init