4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 Copyright (C) Matthias Dieter Wallnöfer 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: objectClass sorting and constraint checking module
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
39 #include "ldb_module.h"
40 #include "dlinklist.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "librpc/ndr/libndr.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "libcli/security/security.h"
45 #include "auth/auth.h"
46 #include "param/param.h"
47 #include "../libds/common/flags.h"
52 struct ldb_module *module;
53 struct ldb_request *req;
54 const struct dsdb_schema *schema;
56 struct ldb_reply *search_res;
57 struct ldb_reply *search_res2;
59 int (*step_fn)(struct oc_context *);
63 struct class_list *prev, *next;
64 const struct dsdb_class *objectclass;
67 static struct oc_context *oc_init_context(struct ldb_module *module,
68 struct ldb_request *req)
70 struct ldb_context *ldb;
71 struct oc_context *ac;
73 ldb = ldb_module_get_ctx(module);
75 ac = talloc_zero(req, struct oc_context);
83 ac->schema = dsdb_get_schema(ldb, ac);
88 static int objectclass_do_add(struct oc_context *ac);
90 /* Sort objectClasses into correct order, and validate that all
91 * objectClasses specified actually exist in the schema
94 static int objectclass_sort(struct ldb_module *module,
95 const struct dsdb_schema *schema,
97 struct ldb_message_element *objectclass_element,
98 struct class_list **sorted_out)
100 struct ldb_context *ldb;
101 unsigned int i, lowest;
102 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
104 ldb = ldb_module_get_ctx(module);
108 * We work on 4 different 'bins' (implemented here as linked lists):
110 * * sorted: the eventual list, in the order we wish to push
111 * into the database. This is the only ordered list.
113 * * parent_class: The current parent class 'bin' we are
114 * trying to find subclasses for
116 * * subclass: The subclasses we have found so far
118 * * unsorted: The remaining objectClasses
120 * The process is a matter of filtering objectClasses up from
121 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
123 * We start with 'top' (found and promoted to parent_class
124 * initially). Then we find (in unsorted) all the direct
125 * subclasses of 'top'. parent_classes is concatenated onto
126 * the end of 'sorted', and subclass becomes the list in
129 * We then repeat, until we find no more subclasses. Any left
130 * over classes are added to the end.
134 /* Firstly, dump all the objectClass elements into the
135 * unsorted bin, except for 'top', which is special */
136 for (i=0; i < objectclass_element->num_values; i++) {
137 current = talloc(mem_ctx, struct class_list);
140 return LDB_ERR_OPERATIONS_ERROR;
142 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
143 if (!current->objectclass) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
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;
148 } else if (current->objectclass->isDefunct) {
149 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
150 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
151 /* This looks weird, but windows apparently returns this for invalid objectClass values */
152 return LDB_ERR_NO_SUCH_ATTRIBUTE;
155 /* Don't add top to list, we will do that later */
156 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
157 DLIST_ADD_END(unsorted, current, struct class_list *);
161 /* Add top here, to prevent duplicates */
162 current = talloc(mem_ctx, struct class_list);
163 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
164 DLIST_ADD_END(sorted, current, struct class_list *);
167 /* For each object: find parent chain */
168 for (current = unsorted; schema && current; current = current->next) {
169 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
170 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
174 /* If we didn't get to the end of the list, we need to add this parent */
175 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
179 new_parent = talloc(mem_ctx, struct class_list);
180 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
181 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
187 current_lowest = NULL;
188 for (current = unsorted; schema && current; current = current->next) {
189 if(current->objectclass->subClass_order < lowest) {
190 current_lowest = current;
191 lowest = current->objectclass->subClass_order;
195 if(current_lowest != NULL) {
196 DLIST_REMOVE(unsorted,current_lowest);
197 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
203 *sorted_out = sorted;
208 /* If we don't have schema yet, then just merge the lists again */
209 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
210 *sorted_out = sorted;
214 /* This shouldn't happen, and would break MMC, perhaps there
215 * was no 'top', a conflict in the objectClasses or some other
218 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
219 return LDB_ERR_OBJECT_CLASS_VIOLATION;
222 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
224 struct ldb_context *ldb;
225 struct oc_context *ac;
228 ac = talloc_get_type(req->context, struct oc_context);
229 ldb = ldb_module_get_ctx(ac->module);
232 return ldb_module_done(ac->req, NULL, NULL,
233 LDB_ERR_OPERATIONS_ERROR);
235 if (ares->error != LDB_SUCCESS &&
236 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
237 return ldb_module_done(ac->req, ares->controls,
238 ares->response, ares->error);
241 ldb_reset_err_string(ldb);
243 switch (ares->type) {
244 case LDB_REPLY_ENTRY:
245 if (ac->search_res != NULL) {
246 ldb_set_errstring(ldb, "Too many results");
248 return ldb_module_done(ac->req, NULL, NULL,
249 LDB_ERR_OPERATIONS_ERROR);
252 ac->search_res = talloc_steal(ac, ares);
255 case LDB_REPLY_REFERRAL:
262 ret = ac->step_fn(ac);
263 if (ret != LDB_SUCCESS) {
264 return ldb_module_done(ac->req, NULL, NULL, ret);
272 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
274 struct oc_context *ac;
276 ac = talloc_get_type(req->context, struct oc_context);
279 return ldb_module_done(ac->req, NULL, NULL,
280 LDB_ERR_OPERATIONS_ERROR);
283 if (ares->type == LDB_REPLY_REFERRAL) {
284 return ldb_module_send_referral(ac->req, ares->referral);
287 if (ares->error != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 if (ares->type != LDB_REPLY_DONE) {
294 return ldb_module_done(ac->req, NULL, NULL,
295 LDB_ERR_OPERATIONS_ERROR);
298 return ldb_module_done(ac->req, ares->controls,
299 ares->response, ares->error);
302 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
304 This should mean that if the parent is:
305 CN=Users,DC=samba,DC=example,DC=com
306 and a proposed child is
307 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
309 The resulting DN should be:
311 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
314 static int fix_dn(TALLOC_CTX *mem_ctx,
315 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
316 struct ldb_dn **fixed_dn)
318 char *upper_rdn_attr;
319 const struct ldb_val *rdn_val;
321 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
322 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
324 /* We need the attribute name in upper case */
325 upper_rdn_attr = strupper_talloc(*fixed_dn,
326 ldb_dn_get_rdn_name(newdn));
327 if (!upper_rdn_attr) {
328 return LDB_ERR_OPERATIONS_ERROR;
331 /* Create a new child */
332 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
333 return LDB_ERR_OPERATIONS_ERROR;
337 rdn_val = ldb_dn_get_rdn_val(newdn);
340 /* the rules for rDN length constraints are more complex than
341 this. Until we understand them we need to leave this
342 constraint out. Otherwise we break replication, as windows
343 does sometimes send us rDNs longer than 64 */
344 if (!rdn_val || rdn_val->length > 64) {
345 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
350 /* And replace it with CN=foo (we need the attribute in upper case */
351 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
355 static int objectclass_do_add(struct oc_context *ac);
357 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
359 struct ldb_context *ldb;
360 struct ldb_request *search_req;
361 struct oc_context *ac;
362 struct ldb_dn *parent_dn;
364 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
366 ldb = ldb_module_get_ctx(module);
368 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
370 /* do not manipulate our control entries */
371 if (ldb_dn_is_special(req->op.add.message->dn)) {
372 return ldb_next_request(module, req);
375 /* the objectClass must be specified on add */
376 if (ldb_msg_find_element(req->op.add.message,
377 "objectClass") == NULL) {
378 return LDB_ERR_OBJECT_CLASS_VIOLATION;
381 ac = oc_init_context(module, req);
383 return LDB_ERR_OPERATIONS_ERROR;
386 /* If there isn't a parent, just go on to the add processing */
387 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
388 return objectclass_do_add(ac);
391 /* get copy of parent DN */
392 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
393 if (parent_dn == NULL) {
395 return LDB_ERR_OPERATIONS_ERROR;
398 ret = ldb_build_search_req(&search_req, ldb,
399 ac, parent_dn, LDB_SCOPE_BASE,
400 "(objectClass=*)", parent_attrs,
402 ac, get_search_callback,
404 if (ret != LDB_SUCCESS) {
408 ac->step_fn = objectclass_do_add;
410 return ldb_next_request(ac->module, search_req);
413 static int objectclass_do_add(struct oc_context *ac)
415 struct ldb_context *ldb;
416 struct ldb_request *add_req;
418 struct ldb_message_element *objectclass_element, *el;
419 struct ldb_message *msg;
421 struct class_list *sorted, *current;
423 const struct dsdb_class *objectclass;
424 int32_t systemFlags = 0;
425 const char *rdn_name = NULL;
427 ldb = ldb_module_get_ctx(ac->module);
429 mem_ctx = talloc_new(ac);
430 if (mem_ctx == NULL) {
432 return LDB_ERR_OPERATIONS_ERROR;
435 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
437 /* Check if we have a valid parent - this check is needed since
438 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
439 if (ac->search_res == NULL) {
440 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
441 /* Allow the tree to be started */
443 /* but don't keep any error string, it's meaningless */
444 ldb_set_errstring(ldb, NULL);
446 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
447 ldb_dn_get_linearized(msg->dn));
448 talloc_free(mem_ctx);
449 return LDB_ERR_NO_SUCH_OBJECT;
453 /* Fix up the DN to be in the standard form, taking
454 * particular care to match the parent DN */
456 ac->req->op.add.message->dn,
457 ac->search_res->message->dn,
460 if (ret != LDB_SUCCESS) {
461 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
462 ldb_dn_get_linearized(ac->req->op.add.message->dn));
463 talloc_free(mem_ctx);
468 if (ac->schema != NULL) {
469 /* This is now the objectClass list from the database */
470 objectclass_element = ldb_msg_find_element(msg, "objectClass");
472 if (!objectclass_element) {
473 /* Where did it go? bail now... */
474 talloc_free(mem_ctx);
475 return LDB_ERR_OPERATIONS_ERROR;
477 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
478 objectclass_element, &sorted);
479 if (ret != LDB_SUCCESS) {
480 talloc_free(mem_ctx);
484 ldb_msg_remove_attr(msg, "objectClass");
485 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
487 if (ret != LDB_SUCCESS) {
488 talloc_free(mem_ctx);
492 /* We must completely replace the existing objectClass entry,
493 * because we need it sorted */
495 /* Move from the linked list back into an ldb msg */
496 for (current = sorted; current; current = current->next) {
497 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
500 talloc_free(mem_ctx);
501 return LDB_ERR_OPERATIONS_ERROR;
503 ret = ldb_msg_add_string(msg, "objectClass", value);
504 if (ret != LDB_SUCCESS) {
505 ldb_set_errstring(ldb,
506 "objectclass: could not re-add sorted "
507 "objectclass to modify msg");
508 talloc_free(mem_ctx);
513 /* Retrive the message again so get_last_structural_class works */
514 objectclass_element = ldb_msg_find_element(msg, "objectClass");
516 /* Make sure its valid to add an object of this type */
517 objectclass = get_last_structural_class(ac->schema,
518 objectclass_element);
519 if(objectclass == NULL) {
520 ldb_asprintf_errstring(ldb,
521 "Failed to find a structural class for %s",
522 ldb_dn_get_linearized(msg->dn));
523 return LDB_ERR_UNWILLING_TO_PERFORM;
526 rdn_name = ldb_dn_get_rdn_name(msg->dn);
527 if (objectclass->rDNAttID
528 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
529 ldb_asprintf_errstring(ldb,
530 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
531 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
532 return LDB_ERR_NAMING_VIOLATION;
535 if (ac->search_res && ac->search_res->message) {
536 struct ldb_message_element *oc_el
537 = ldb_msg_find_element(ac->search_res->message, "objectClass");
539 bool allowed_class = false;
541 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
542 const struct dsdb_class *sclass;
544 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
547 /* We don't know this class? what is going on? */
550 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
551 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
552 allowed_class = true;
558 if (!allowed_class) {
559 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
560 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
561 return LDB_ERR_NAMING_VIOLATION;
565 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
566 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
567 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
568 return LDB_ERR_UNWILLING_TO_PERFORM;
571 if (!ldb_msg_find_element(msg, "objectCategory")) {
572 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
573 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
574 /* Strip off extended components */
575 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
576 value = ldb_dn_alloc_linearized(msg, dn);
579 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
583 talloc_free(mem_ctx);
584 return LDB_ERR_OPERATIONS_ERROR;
586 ldb_msg_add_string(msg, "objectCategory", value);
588 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
589 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
593 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
594 el = ldb_msg_find_element(msg, "systemFlags");
596 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
599 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
600 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
601 ldb_msg_remove_element(msg, el);
604 /* This flag is only allowed on attributeSchema objects */
605 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
606 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
609 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
610 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
611 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
612 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
613 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
614 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
616 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
617 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
618 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
619 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
622 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
624 if (el || systemFlags != 0) {
625 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
629 talloc_free(mem_ctx);
630 ret = ldb_msg_sanity_check(ldb, msg);
633 if (ret != LDB_SUCCESS) {
637 ret = ldb_build_add_req(&add_req, ldb, ac,
642 if (ret != LDB_SUCCESS) {
646 /* perform the add */
647 return ldb_next_request(ac->module, add_req);
650 static int oc_modify_callback(struct ldb_request *req,
651 struct ldb_reply *ares);
652 static int objectclass_do_mod(struct oc_context *ac);
654 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
656 struct ldb_context *ldb = ldb_module_get_ctx(module);
657 struct ldb_message_element *objectclass_element;
658 struct ldb_message *msg;
659 struct class_list *sorted, *current;
660 struct ldb_request *down_req;
661 struct oc_context *ac;
666 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
668 /* do not manipulate our control entries */
669 if (ldb_dn_is_special(req->op.mod.message->dn)) {
670 return ldb_next_request(module, req);
673 /* As with the "real" AD we don't accept empty messages */
674 if (req->op.mod.message->num_elements == 0) {
675 ldb_set_errstring(ldb, "objectclass: modify message must have "
676 "elements/attributes!");
677 return LDB_ERR_UNWILLING_TO_PERFORM;
680 ac = oc_init_context(module, req);
682 return LDB_ERR_OPERATIONS_ERROR;
685 if (ac->schema == NULL) {
686 /* Without schema, there isn't much to do here */
688 return ldb_next_request(module, req);
691 /* If no part of this touches the objectClass, then we don't
692 * need to make any changes. */
693 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
695 /* If the only operation is the deletion of the objectClass
696 * then go on with just fixing the attribute case */
697 if (!objectclass_element) {
698 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
700 return LDB_ERR_OPERATIONS_ERROR;
703 ret = ldb_build_mod_req(&down_req, ldb, ac,
708 if (ret != LDB_SUCCESS) {
712 /* go on with the call chain */
713 return ldb_next_request(module, down_req);
716 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
717 case LDB_FLAG_MOD_DELETE:
718 if (objectclass_element->num_values == 0) {
719 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
723 case LDB_FLAG_MOD_REPLACE:
724 mem_ctx = talloc_new(ac);
725 if (mem_ctx == NULL) {
726 return LDB_ERR_OPERATIONS_ERROR;
729 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
731 talloc_free(mem_ctx);
732 return LDB_ERR_OPERATIONS_ERROR;
735 ret = objectclass_sort(module, ac->schema, mem_ctx,
736 objectclass_element, &sorted);
737 if (ret != LDB_SUCCESS) {
738 talloc_free(mem_ctx);
742 /* We must completely replace the existing objectClass entry,
743 * because we need it sorted */
745 ldb_msg_remove_attr(msg, "objectClass");
746 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
748 if (ret != LDB_SUCCESS) {
749 talloc_free(mem_ctx);
753 /* Move from the linked list back into an ldb msg */
754 for (current = sorted; current; current = current->next) {
755 /* copy the value as this string is on the schema
756 * context and we can't rely on it not changing
757 * before the operation is over */
758 value = talloc_strdup(msg,
759 current->objectclass->lDAPDisplayName);
762 talloc_free(mem_ctx);
763 return LDB_ERR_OPERATIONS_ERROR;
765 ret = ldb_msg_add_string(msg, "objectClass", value);
766 if (ret != LDB_SUCCESS) {
767 ldb_set_errstring(ldb,
768 "objectclass: could not re-add sorted "
769 "objectclass to modify msg");
770 talloc_free(mem_ctx);
775 talloc_free(mem_ctx);
777 ret = ldb_msg_sanity_check(ldb, msg);
778 if (ret != LDB_SUCCESS) {
782 ret = ldb_build_mod_req(&down_req, ldb, ac,
787 if (ret != LDB_SUCCESS) {
791 /* go on with the call chain */
792 return ldb_next_request(module, down_req);
795 /* This isn't the default branch of the switch, but a 'in any
796 * other case'. When a delete isn't for all objectClasses for
800 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
803 return LDB_ERR_OPERATIONS_ERROR;
806 ret = ldb_build_mod_req(&down_req, ldb, ac,
809 ac, oc_modify_callback,
811 if (ret != LDB_SUCCESS) {
815 return ldb_next_request(module, down_req);
818 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
820 struct ldb_context *ldb;
821 static const char * const attrs[] = { "objectClass", NULL };
822 struct ldb_request *search_req;
823 struct oc_context *ac;
826 ac = talloc_get_type(req->context, struct oc_context);
827 ldb = ldb_module_get_ctx(ac->module);
830 return ldb_module_done(ac->req, NULL, NULL,
831 LDB_ERR_OPERATIONS_ERROR);
834 if (ares->type == LDB_REPLY_REFERRAL) {
835 return ldb_module_send_referral(ac->req, ares->referral);
838 if (ares->error != LDB_SUCCESS) {
839 return ldb_module_done(ac->req, ares->controls,
840 ares->response, ares->error);
843 if (ares->type != LDB_REPLY_DONE) {
845 return ldb_module_done(ac->req, NULL, NULL,
846 LDB_ERR_OPERATIONS_ERROR);
851 ret = ldb_build_search_req(&search_req, ldb, ac,
852 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
855 ac, get_search_callback,
857 if (ret != LDB_SUCCESS) {
858 return ldb_module_done(ac->req, NULL, NULL, ret);
861 ac->step_fn = objectclass_do_mod;
863 ret = ldb_next_request(ac->module, search_req);
864 if (ret != LDB_SUCCESS) {
865 return ldb_module_done(ac->req, NULL, NULL, ret);
870 static int objectclass_do_mod(struct oc_context *ac)
872 struct ldb_context *ldb;
873 struct ldb_request *mod_req;
875 struct ldb_message_element *objectclass_element;
876 struct ldb_message *msg;
878 struct class_list *sorted, *current;
881 ldb = ldb_module_get_ctx(ac->module);
883 if (ac->search_res == NULL) {
884 return LDB_ERR_OPERATIONS_ERROR;
887 mem_ctx = talloc_new(ac);
888 if (mem_ctx == NULL) {
889 return LDB_ERR_OPERATIONS_ERROR;
892 /* use a new message structure */
893 msg = ldb_msg_new(ac);
895 ldb_set_errstring(ldb,
896 "objectclass: could not create new modify msg");
897 talloc_free(mem_ctx);
898 return LDB_ERR_OPERATIONS_ERROR;
901 /* This is now the objectClass list from the database */
902 objectclass_element = ldb_msg_find_element(ac->search_res->message,
904 if (!objectclass_element) {
905 /* Where did it go? bail now... */
906 talloc_free(mem_ctx);
907 return LDB_ERR_OPERATIONS_ERROR;
911 msg->dn = ac->req->op.mod.message->dn;
913 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
914 objectclass_element, &sorted);
915 if (ret != LDB_SUCCESS) {
919 /* We must completely replace the existing objectClass entry.
920 * We could do a constrained add/del, but we are meant to be
921 * in a transaction... */
923 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
924 if (ret != LDB_SUCCESS) {
925 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
926 talloc_free(mem_ctx);
930 /* Move from the linked list back into an ldb msg */
931 for (current = sorted; current; current = current->next) {
932 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
935 return LDB_ERR_OPERATIONS_ERROR;
937 ret = ldb_msg_add_string(msg, "objectClass", value);
938 if (ret != LDB_SUCCESS) {
939 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
940 talloc_free(mem_ctx);
945 ret = ldb_msg_sanity_check(ldb, msg);
946 if (ret != LDB_SUCCESS) {
947 talloc_free(mem_ctx);
951 ret = ldb_build_mod_req(&mod_req, ldb, ac,
956 if (ret != LDB_SUCCESS) {
957 talloc_free(mem_ctx);
961 talloc_free(mem_ctx);
962 /* perform the modify */
963 return ldb_next_request(ac->module, mod_req);
966 static int objectclass_do_rename(struct oc_context *ac);
968 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
970 static const char * const attrs[] = { "objectClass", NULL };
971 struct ldb_context *ldb;
972 struct ldb_request *search_req;
973 struct oc_context *ac;
974 struct ldb_dn *parent_dn;
977 ldb = ldb_module_get_ctx(module);
979 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
981 /* do not manipulate our control entries */
982 if (ldb_dn_is_special(req->op.rename.newdn)) {
983 return ldb_next_request(module, req);
986 ac = oc_init_context(module, req);
988 return LDB_ERR_OPERATIONS_ERROR;
991 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
992 if (parent_dn == NULL) {
994 return LDB_ERR_OPERATIONS_ERROR;
997 /* this looks up the parent object for fetching some important
998 * informations (objectclasses, DN normalisation...) */
999 ret = ldb_build_search_req(&search_req, ldb,
1000 ac, parent_dn, LDB_SCOPE_BASE,
1003 ac, get_search_callback,
1005 if (ret != LDB_SUCCESS) {
1009 /* we have to add the show deleted control, as otherwise DRS
1010 deletes will be refused as we will think the target parent
1012 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1014 if (ret != LDB_SUCCESS) {
1018 ac->step_fn = objectclass_do_rename;
1020 return ldb_next_request(ac->module, search_req);
1023 static int objectclass_do_rename2(struct oc_context *ac);
1025 static int objectclass_do_rename(struct oc_context *ac)
1027 static const char * const attrs[] = { "objectClass", NULL };
1028 struct ldb_context *ldb;
1029 struct ldb_request *search_req;
1032 ldb = ldb_module_get_ctx(ac->module);
1034 /* Check if we have a valid parent - this check is needed since
1035 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1036 if (ac->search_res == NULL) {
1037 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1038 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1039 return LDB_ERR_OTHER;
1042 /* now assign "search_res2" to the parent entry to have "search_res"
1043 * free for another lookup */
1044 ac->search_res2 = ac->search_res;
1045 ac->search_res = NULL;
1047 /* this looks up the real existing object for fetching some important
1048 * informations (objectclasses) */
1049 ret = ldb_build_search_req(&search_req, ldb,
1050 ac, ac->req->op.rename.olddn,
1054 ac, get_search_callback,
1056 if (ret != LDB_SUCCESS) {
1060 ac->step_fn = objectclass_do_rename2;
1062 return ldb_next_request(ac->module, search_req);
1065 static int objectclass_do_rename2(struct oc_context *ac)
1067 struct ldb_context *ldb;
1068 struct ldb_request *rename_req;
1069 struct ldb_dn *fixed_dn;
1072 ldb = ldb_module_get_ctx(ac->module);
1074 /* Check if we have a valid entry - this check is needed since
1075 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1076 if (ac->search_res == NULL) {
1077 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1078 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1079 return LDB_ERR_NO_SUCH_OBJECT;
1082 if (ac->schema != NULL) {
1083 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1084 const struct dsdb_class *objectclass;
1085 const char *rdn_name;
1086 bool allowed_class = false;
1089 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1091 if (oc_el_entry == NULL) {
1092 /* existing entry without a valid object class? */
1093 return LDB_ERR_OPERATIONS_ERROR;
1095 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1096 if (objectclass == NULL) {
1097 /* existing entry without a valid object class? */
1098 return LDB_ERR_OPERATIONS_ERROR;
1101 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1102 if ((objectclass->rDNAttID != NULL) &&
1103 (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1104 ldb_asprintf_errstring(ldb,
1105 "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1107 objectclass->lDAPDisplayName,
1108 objectclass->rDNAttID);
1109 return LDB_ERR_UNWILLING_TO_PERFORM;
1112 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1114 if (oc_el_parent == NULL) {
1115 /* existing entry without a valid object class? */
1116 return LDB_ERR_OPERATIONS_ERROR;
1119 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1120 const struct dsdb_class *sclass;
1122 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1123 &oc_el_parent->values[i]);
1125 /* We don't know this class? what is going on? */
1128 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1129 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1130 allowed_class = true;
1136 if (!allowed_class) {
1137 ldb_asprintf_errstring(ldb,
1138 "objectclass: structural objectClass %s is not a valid child class for %s",
1139 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1140 return LDB_ERR_NAMING_VIOLATION;
1144 /* Ensure we are not trying to rename it to be a child of itself */
1145 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1146 ac->req->op.rename.newdn) == 0) &&
1147 (ldb_dn_compare(ac->req->op.rename.olddn,
1148 ac->req->op.rename.newdn) != 0)) {
1149 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1150 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1151 return LDB_ERR_UNWILLING_TO_PERFORM;
1154 /* Fix up the DN to be in the standard form, taking
1155 * particular care to match the parent DN */
1157 ac->req->op.rename.newdn,
1158 ac->search_res2->message->dn,
1160 if (ret != LDB_SUCCESS) {
1161 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1162 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1167 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1168 ac->req->op.rename.olddn, fixed_dn,
1172 if (ret != LDB_SUCCESS) {
1176 /* perform the rename */
1177 return ldb_next_request(ac->module, rename_req);
1180 static int objectclass_init(struct ldb_module *module)
1182 struct ldb_context *ldb = ldb_module_get_ctx(module);
1184 /* Init everything else */
1185 ret = ldb_next_init(module);
1186 if (ret != LDB_SUCCESS) {
1190 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1191 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1196 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1197 .name = "objectclass",
1198 .add = objectclass_add,
1199 .modify = objectclass_modify,
1200 .rename = objectclass_rename,
1201 .init_context = objectclass_init