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-2011
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 "dsdb/samdb/samdb.h"
41 #include "librpc/ndr/libndr.h"
42 #include "librpc/gen_ndr/ndr_security.h"
43 #include "libcli/security/security.h"
44 #include "auth/auth.h"
45 #include "param/param.h"
46 #include "../libds/common/flags.h"
47 #include "dsdb/samdb/ldb_modules/util.h"
51 struct ldb_module *module;
52 struct ldb_request *req;
53 const struct dsdb_schema *schema;
55 struct ldb_reply *search_res;
56 struct ldb_reply *search_res2;
58 int (*step_fn)(struct oc_context *);
61 static struct oc_context *oc_init_context(struct ldb_module *module,
62 struct ldb_request *req)
64 struct ldb_context *ldb;
65 struct oc_context *ac;
67 ldb = ldb_module_get_ctx(module);
69 ac = talloc_zero(req, struct oc_context);
77 ac->schema = dsdb_get_schema(ldb, ac);
82 static int objectclass_do_add(struct oc_context *ac);
85 * This checks if we have unrelated object classes in our entry's "objectClass"
86 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
87 * or two or more disjunct structural ones.
88 * If one of these conditions are true, blame.
90 static int check_unrelated_objectclasses(struct ldb_module *module,
91 const struct dsdb_schema *schema,
92 const struct dsdb_class *struct_objectclass,
93 struct ldb_message_element *objectclass_element)
95 struct ldb_context *ldb = ldb_module_get_ctx(module);
103 for (i = 0; i < objectclass_element->num_values; i++) {
104 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
105 &objectclass_element->values[i]);
106 const struct dsdb_class *tmp_class2 = struct_objectclass;
108 /* Pointer comparison can be used due to the same schema str. */
109 if (tmp_class == NULL ||
110 tmp_class == struct_objectclass ||
111 tmp_class->objectClassCategory > 2 ||
112 ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
118 ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
119 tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
120 tmp_class2->subClassOf);
121 if (tmp_class2 == tmp_class) {
129 ldb_asprintf_errstring(ldb,
130 "objectclass: the objectclass '%s' seems to be unrelated to %s!",
131 tmp_class->lDAPDisplayName,
132 struct_objectclass->lDAPDisplayName);
133 return LDB_ERR_OBJECT_CLASS_VIOLATION;
139 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
141 struct ldb_context *ldb;
142 struct oc_context *ac;
145 ac = talloc_get_type(req->context, struct oc_context);
146 ldb = ldb_module_get_ctx(ac->module);
149 return ldb_module_done(ac->req, NULL, NULL,
150 LDB_ERR_OPERATIONS_ERROR);
152 if (ares->error != LDB_SUCCESS &&
153 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
154 return ldb_module_done(ac->req, ares->controls,
155 ares->response, ares->error);
158 ldb_reset_err_string(ldb);
160 switch (ares->type) {
161 case LDB_REPLY_ENTRY:
162 if (ac->search_res != NULL) {
163 ldb_set_errstring(ldb, "Too many results");
165 return ldb_module_done(ac->req, NULL, NULL,
166 LDB_ERR_OPERATIONS_ERROR);
169 ac->search_res = talloc_steal(ac, ares);
172 case LDB_REPLY_REFERRAL:
179 ret = ac->step_fn(ac);
180 if (ret != LDB_SUCCESS) {
181 return ldb_module_done(ac->req, NULL, NULL, ret);
189 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
191 This should mean that if the parent is:
192 CN=Users,DC=samba,DC=example,DC=com
193 and a proposed child is
194 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
196 The resulting DN should be:
198 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
201 static int fix_dn(struct ldb_context *ldb,
203 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
204 struct ldb_dn **fixed_dn)
206 char *upper_rdn_attr;
207 const struct ldb_val *rdn_val;
209 /* Fix up the DN to be in the standard form, taking particular care to
210 * match the parent DN */
211 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
212 if (*fixed_dn == NULL) {
216 /* We need the attribute name in upper case */
217 upper_rdn_attr = strupper_talloc(*fixed_dn,
218 ldb_dn_get_rdn_name(newdn));
219 if (upper_rdn_attr == NULL) {
223 /* Create a new child */
224 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
225 return ldb_operr(ldb);
228 rdn_val = ldb_dn_get_rdn_val(newdn);
229 if (rdn_val == NULL) {
230 return ldb_operr(ldb);
234 /* the rules for rDN length constraints are more complex than
235 this. Until we understand them we need to leave this
236 constraint out. Otherwise we break replication, as windows
237 does sometimes send us rDNs longer than 64 */
238 if (!rdn_val || rdn_val->length > 64) {
239 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
244 /* And replace it with CN=foo (we need the attribute in upper case) */
245 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
249 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
251 struct ldb_context *ldb;
252 struct ldb_request *search_req;
253 struct oc_context *ac;
254 struct ldb_dn *parent_dn;
255 const struct ldb_val *val;
257 static const char * const parent_attrs[] = { "objectClass", NULL };
259 ldb = ldb_module_get_ctx(module);
261 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
263 /* do not manipulate our control entries */
264 if (ldb_dn_is_special(req->op.add.message->dn)) {
265 return ldb_next_request(module, req);
268 /* An add operation on the basedn without "NC-add" operation isn't
270 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
271 unsigned int instanceType;
273 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
275 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
277 /* When we are trying to readd the root basedn then
278 * this is denied, but with an interesting mechanism:
279 * there is generated a referral with the last
280 * component value as hostname. */
281 val = ldb_dn_get_component_val(req->op.add.message->dn,
282 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
284 return ldb_operr(ldb);
286 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
287 ldb_dn_get_linearized(req->op.add.message->dn));
288 if (referral_uri == NULL) {
289 return ldb_module_oom(module);
292 return ldb_module_send_referral(req, referral_uri);
296 ac = oc_init_context(module, req);
298 return ldb_operr(ldb);
301 /* If there isn't a parent, just go on to the add processing */
302 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
303 return objectclass_do_add(ac);
306 /* get copy of parent DN */
307 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
308 if (parent_dn == NULL) {
309 return ldb_operr(ldb);
312 ret = ldb_build_search_req(&search_req, ldb,
313 ac, parent_dn, LDB_SCOPE_BASE,
314 "(objectClass=*)", parent_attrs,
316 ac, get_search_callback,
318 LDB_REQ_SET_LOCATION(search_req);
319 if (ret != LDB_SUCCESS) {
323 ret = dsdb_request_add_controls(search_req,
324 DSDB_FLAG_AS_SYSTEM |
325 DSDB_SEARCH_SHOW_RECYCLED);
326 if (ret != LDB_SUCCESS) {
330 ac->step_fn = objectclass_do_add;
332 return ldb_next_request(ac->module, search_req);
337 check if this is a special RODC nTDSDSA add
339 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
340 const struct dsdb_class *objectclass)
342 struct ldb_control *rodc_control;
344 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
347 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
352 rodc_control->critical = false;
356 static int objectclass_do_add(struct oc_context *ac)
358 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
359 struct ldb_request *add_req;
360 struct ldb_message_element *objectclass_element, *el;
361 struct ldb_message *msg;
362 const char *rdn_name = NULL;
364 const struct dsdb_class *objectclass;
365 struct ldb_dn *objectcategory;
366 int32_t systemFlags = 0;
371 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
373 return ldb_module_oom(ac->module);
376 /* Check if we have a valid parent - this check is needed since
377 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
378 if (ac->search_res == NULL) {
379 unsigned int instanceType;
381 /* An add operation on partition DNs without "NC-add" operation
383 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
385 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
386 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
387 ldb_dn_get_linearized(msg->dn));
388 return LDB_ERR_NO_SUCH_OBJECT;
391 /* Don't keep any error messages - we've to add a partition */
392 ldb_set_errstring(ldb, NULL);
394 /* Fix up the DN to be in the standard form, taking
395 * particular care to match the parent DN */
396 ret = fix_dn(ldb, msg,
397 ac->req->op.add.message->dn,
398 ac->search_res->message->dn,
400 if (ret != LDB_SUCCESS) {
401 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
402 ldb_dn_get_linearized(ac->req->op.add.message->dn));
407 if (ac->schema != NULL) {
408 unsigned int linkID = 0;
410 * Notice: by the normalization function call in "ldb_request()"
411 * case "LDB_ADD" we have always only *one* "objectClass"
412 * attribute at this stage!
415 objectclass_element = ldb_msg_find_element(msg, "objectClass");
416 if (!objectclass_element) {
417 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
418 ldb_dn_get_linearized(msg->dn));
419 return LDB_ERR_OBJECT_CLASS_VIOLATION;
421 if (objectclass_element->num_values == 0) {
422 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
423 ldb_dn_get_linearized(msg->dn));
424 return LDB_ERR_CONSTRAINT_VIOLATION;
427 /* Now do the sorting */
428 ret = dsdb_sort_objectClass_attr(ldb, ac->schema,
429 objectclass_element, msg,
430 objectclass_element);
431 if (ret != LDB_SUCCESS) {
436 * Get the new top-most structural object class and check for
437 * unrelated structural classes
439 objectclass = dsdb_get_last_structural_class(ac->schema,
440 objectclass_element);
441 if (objectclass == NULL) {
442 ldb_asprintf_errstring(ldb,
443 "Failed to find a structural class for %s",
444 ldb_dn_get_linearized(msg->dn));
445 return LDB_ERR_UNWILLING_TO_PERFORM;
448 ret = check_unrelated_objectclasses(ac->module, ac->schema,
450 objectclass_element);
451 if (ret != LDB_SUCCESS) {
455 rdn_name = ldb_dn_get_rdn_name(msg->dn);
456 if (rdn_name == NULL) {
457 return ldb_operr(ldb);
460 for (i = 0; (!found) && (i < objectclass_element->num_values);
462 const struct dsdb_class *tmp_class =
463 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
464 &objectclass_element->values[i]);
466 if (tmp_class == NULL) continue;
468 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
472 ldb_asprintf_errstring(ldb,
473 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
474 rdn_name, objectclass->lDAPDisplayName);
475 return LDB_ERR_NAMING_VIOLATION;
478 if (objectclass->systemOnly &&
479 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
480 !check_rodc_ntdsdsa_add(ac, objectclass)) {
481 ldb_asprintf_errstring(ldb,
482 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
483 objectclass->lDAPDisplayName,
484 ldb_dn_get_linearized(msg->dn));
485 return LDB_ERR_UNWILLING_TO_PERFORM;
488 if (ac->search_res && ac->search_res->message) {
489 struct ldb_message_element *oc_el
490 = ldb_msg_find_element(ac->search_res->message, "objectClass");
492 bool allowed_class = false;
493 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
494 const struct dsdb_class *sclass;
496 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
499 /* We don't know this class? what is going on? */
502 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
503 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
504 allowed_class = true;
510 if (!allowed_class) {
511 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
512 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
513 return LDB_ERR_NAMING_VIOLATION;
517 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
519 if (objectcategory == NULL) {
520 struct dsdb_extended_dn_store_format *dn_format =
521 talloc_get_type(ldb_module_get_private(ac->module),
522 struct dsdb_extended_dn_store_format);
523 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
524 /* Strip off extended components */
525 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
526 objectclass->defaultObjectCategory);
527 value = ldb_dn_alloc_linearized(msg, dn);
530 value = talloc_strdup(msg,
531 objectclass->defaultObjectCategory);
534 return ldb_module_oom(ac->module);
537 ret = ldb_msg_add_string(msg, "objectCategory", value);
538 if (ret != LDB_SUCCESS) {
542 const struct dsdb_class *ocClass =
543 dsdb_class_by_cn_ldb_val(ac->schema,
544 ldb_dn_get_rdn_val(objectcategory));
545 if (ocClass != NULL) {
546 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
547 ocClass->defaultObjectCategory);
548 if (ldb_dn_compare(objectcategory, dn) != 0) {
552 talloc_free(objectcategory);
553 if (ocClass == NULL) {
554 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
555 ldb_dn_get_linearized(msg->dn));
556 return LDB_ERR_OBJECT_CLASS_VIOLATION;
560 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
561 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
565 /* There are very special rules for systemFlags, see MS-ADTS
566 * MS-ADTS 3.1.1.5.2.4 */
568 el = ldb_msg_find_element(msg, "systemFlags");
569 if ((el != NULL) && (el->num_values > 1)) {
570 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
571 ldb_dn_get_linearized(msg->dn));
572 return LDB_ERR_CONSTRAINT_VIOLATION;
575 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
577 ldb_msg_remove_attr(msg, "systemFlags");
579 /* Only the following flags may be set by a client */
580 if (ldb_request_get_control(ac->req,
581 LDB_CONTROL_RELAX_OID) == NULL) {
582 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
583 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
584 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
585 | SYSTEM_FLAG_ATTR_IS_RDN );
588 /* But the last one ("ATTR_IS_RDN") is only allowed on
589 * "attributeSchema" objects. So truncate if it does not fit. */
590 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
591 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
594 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
595 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
596 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
597 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
598 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
599 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
600 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
601 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
602 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
603 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
604 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
605 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
606 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
608 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
610 linkID = ldb_msg_find_attr_as_int(msg, "linkID", 0);
611 if (linkID > 0 && linkID % 2 == 1) {
612 systemFlags |= DS_FLAG_ATTR_NOT_REPLICATED;
615 if (el || systemFlags != 0) {
616 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
618 if (ret != LDB_SUCCESS) {
623 /* make sure that "isCriticalSystemObject" is not specified! */
624 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
626 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
627 ldb_set_errstring(ldb,
628 "objectclass: 'isCriticalSystemObject' must not be specified!");
629 return LDB_ERR_UNWILLING_TO_PERFORM;
633 ret = ldb_build_add_req(&add_req, ldb, ac,
636 ac->req, dsdb_next_callback,
638 LDB_REQ_SET_LOCATION(add_req);
639 if (ret != LDB_SUCCESS) {
643 /* perform the add */
644 return ldb_next_request(ac->module, add_req);
647 static int oc_modify_callback(struct ldb_request *req,
648 struct ldb_reply *ares);
649 static int objectclass_do_mod(struct oc_context *ac);
651 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
653 struct ldb_context *ldb = ldb_module_get_ctx(module);
654 struct ldb_message_element *objectclass_element;
655 struct ldb_message *msg;
656 struct ldb_request *down_req;
657 struct oc_context *ac;
658 bool oc_changes = false;
661 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
663 /* do not manipulate our control entries */
664 if (ldb_dn_is_special(req->op.mod.message->dn)) {
665 return ldb_next_request(module, req);
668 /* As with the "real" AD we don't accept empty messages */
669 if (req->op.mod.message->num_elements == 0) {
670 ldb_set_errstring(ldb, "objectclass: modify message must have "
671 "elements/attributes!");
672 return LDB_ERR_UNWILLING_TO_PERFORM;
675 ac = oc_init_context(module, req);
677 return ldb_operr(ldb);
680 /* Without schema, there isn't much to do here */
681 if (ac->schema == NULL) {
683 return ldb_next_request(module, req);
686 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
688 return ldb_module_oom(ac->module);
691 /* For now change everything except the objectclasses */
693 objectclass_element = ldb_msg_find_element(msg, "objectClass");
694 if (objectclass_element != NULL) {
695 ldb_msg_remove_attr(msg, "objectClass");
699 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
700 * only on application NCs - not on the default ones */
702 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
703 struct ldb_dn *nc_root;
705 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
707 if (ret != LDB_SUCCESS) {
711 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
712 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
713 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
714 ldb_set_errstring(ldb,
715 "objectclass: object class changes on objects under the standard name contexts not allowed!");
716 return LDB_ERR_UNWILLING_TO_PERFORM;
719 talloc_free(nc_root);
723 ret = ldb_build_mod_req(&down_req, ldb, ac,
729 ret = ldb_build_mod_req(&down_req, ldb, ac,
735 LDB_REQ_SET_LOCATION(down_req);
736 if (ret != LDB_SUCCESS) {
740 return ldb_next_request(module, down_req);
743 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
745 static const char * const attrs[] = { "objectClass", NULL };
746 struct ldb_context *ldb;
747 struct ldb_request *search_req;
748 struct oc_context *ac;
751 ac = talloc_get_type(req->context, struct oc_context);
752 ldb = ldb_module_get_ctx(ac->module);
755 return ldb_module_done(ac->req, NULL, NULL,
756 LDB_ERR_OPERATIONS_ERROR);
759 if (ares->type == LDB_REPLY_REFERRAL) {
760 return ldb_module_send_referral(ac->req, ares->referral);
763 if (ares->error != LDB_SUCCESS) {
764 return ldb_module_done(ac->req, ares->controls,
765 ares->response, ares->error);
768 if (ares->type != LDB_REPLY_DONE) {
770 return ldb_module_done(ac->req, NULL, NULL,
771 LDB_ERR_OPERATIONS_ERROR);
776 /* this looks up the real existing object for fetching some important
777 * information (objectclasses) */
778 ret = ldb_build_search_req(&search_req, ldb,
779 ac, ac->req->op.mod.message->dn,
783 ac, get_search_callback,
785 LDB_REQ_SET_LOCATION(search_req);
786 if (ret != LDB_SUCCESS) {
787 return ldb_module_done(ac->req, NULL, NULL, ret);
790 ret = dsdb_request_add_controls(search_req,
791 DSDB_FLAG_AS_SYSTEM |
792 DSDB_SEARCH_SHOW_RECYCLED);
793 if (ret != LDB_SUCCESS) {
794 return ldb_module_done(ac->req, NULL, NULL, ret);
797 ac->step_fn = objectclass_do_mod;
799 ret = ldb_next_request(ac->module, search_req);
800 if (ret != LDB_SUCCESS) {
801 return ldb_module_done(ac->req, NULL, NULL, ret);
807 static int objectclass_do_mod(struct oc_context *ac)
809 struct ldb_context *ldb;
810 struct ldb_request *mod_req;
811 struct ldb_message_element *oc_el_entry, *oc_el_change;
812 struct ldb_val *vals;
813 struct ldb_message *msg;
814 const struct dsdb_class *objectclass;
815 unsigned int i, j, k;
819 ldb = ldb_module_get_ctx(ac->module);
821 /* we should always have a valid entry when we enter here */
822 if (ac->search_res == NULL) {
823 return ldb_operr(ldb);
826 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
828 if (oc_el_entry == NULL) {
829 /* existing entry without a valid object class? */
830 return ldb_operr(ldb);
833 /* use a new message structure */
834 msg = ldb_msg_new(ac);
836 return ldb_module_oom(ac->module);
839 msg->dn = ac->req->op.mod.message->dn;
841 /* We've to walk over all "objectClass" message elements */
842 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
843 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
844 "objectClass") != 0) {
848 oc_el_change = &ac->req->op.mod.message->elements[k];
850 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
851 case LDB_FLAG_MOD_ADD:
852 /* Merge the two message elements */
853 for (i = 0; i < oc_el_change->num_values; i++) {
854 for (j = 0; j < oc_el_entry->num_values; j++) {
855 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
856 (char *)oc_el_entry->values[j].data) == 0) {
857 ldb_asprintf_errstring(ldb,
858 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
859 (int)oc_el_change->values[i].length,
860 (const char *)oc_el_change->values[i].data);
861 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
864 /* append the new object class value - code was
865 * copied from "ldb_msg_add_value" */
866 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
868 oc_el_entry->num_values + 1);
870 return ldb_module_oom(ac->module);
872 oc_el_entry->values = vals;
873 oc_el_entry->values[oc_el_entry->num_values] =
874 oc_el_change->values[i];
875 ++(oc_el_entry->num_values);
880 case LDB_FLAG_MOD_REPLACE:
882 * In this case the new "oc_el_entry" is simply
885 oc_el_entry = oc_el_change;
889 case LDB_FLAG_MOD_DELETE:
890 /* Merge the two message elements */
891 for (i = 0; i < oc_el_change->num_values; i++) {
893 for (j = 0; j < oc_el_entry->num_values; j++) {
894 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
895 (char *)oc_el_entry->values[j].data) == 0) {
897 /* delete the object class value
898 * - code was copied from
899 * "ldb_msg_remove_element" */
900 if (j != oc_el_entry->num_values - 1) {
901 memmove(&oc_el_entry->values[j],
902 &oc_el_entry->values[j+1],
903 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
905 --(oc_el_entry->num_values);
910 /* we cannot delete a not existing
912 ldb_asprintf_errstring(ldb,
913 "objectclass: cannot delete this objectclass: '%.*s'!",
914 (int)oc_el_change->values[i].length,
915 (const char *)oc_el_change->values[i].data);
916 return LDB_ERR_NO_SUCH_ATTRIBUTE;
923 /* Now do the sorting */
924 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, oc_el_entry,
926 if (ret != LDB_SUCCESS) {
931 * Get the new top-most structural object class and check for
932 * unrelated structural classes
934 objectclass = dsdb_get_last_structural_class(ac->schema,
936 if (objectclass == NULL) {
937 ldb_set_errstring(ldb,
938 "objectclass: cannot delete all structural objectclasses!");
939 return LDB_ERR_OBJECT_CLASS_VIOLATION;
942 /* Check for unrelated objectclasses */
943 ret = check_unrelated_objectclasses(ac->module, ac->schema,
946 if (ret != LDB_SUCCESS) {
951 /* Now add the new object class attribute to the change message */
952 ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
953 if (ret != LDB_SUCCESS) {
954 ldb_module_oom(ac->module);
958 /* Now we have the real and definitive change left to do */
960 ret = ldb_build_mod_req(&mod_req, ldb, ac,
963 ac->req, dsdb_next_callback,
965 LDB_REQ_SET_LOCATION(mod_req);
966 if (ret != LDB_SUCCESS) {
970 return ldb_next_request(ac->module, mod_req);
973 static int objectclass_do_rename(struct oc_context *ac);
975 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
977 static const char * const attrs[] = { "objectClass", NULL };
978 struct ldb_context *ldb;
979 struct ldb_request *search_req;
980 struct oc_context *ac;
981 struct ldb_dn *parent_dn;
984 ldb = ldb_module_get_ctx(module);
986 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
988 /* do not manipulate our control entries */
989 if (ldb_dn_is_special(req->op.rename.olddn)) {
990 return ldb_next_request(module, req);
994 * Bypass the constraint checks when we do have the "DBCHECK" control
995 * set, so we can force objects under the deleted objects container.
997 if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK) != NULL) {
998 return ldb_next_request(module, req);
1001 ac = oc_init_context(module, req);
1003 return ldb_operr(ldb);
1006 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1007 if (parent_dn == NULL) {
1008 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1009 ldb_dn_get_linearized(req->op.rename.olddn));
1010 return LDB_ERR_NO_SUCH_OBJECT;
1013 /* this looks up the parent object for fetching some important
1014 * information (objectclasses, DN normalisation...) */
1015 ret = ldb_build_search_req(&search_req, ldb,
1016 ac, parent_dn, LDB_SCOPE_BASE,
1019 ac, get_search_callback,
1021 LDB_REQ_SET_LOCATION(search_req);
1022 if (ret != LDB_SUCCESS) {
1026 /* we have to add the show recycled control, as otherwise DRS
1027 deletes will be refused as we will think the target parent
1029 ret = dsdb_request_add_controls(search_req,
1030 DSDB_FLAG_AS_SYSTEM |
1031 DSDB_SEARCH_SHOW_RECYCLED);
1032 if (ret != LDB_SUCCESS) {
1036 ac->step_fn = objectclass_do_rename;
1038 return ldb_next_request(ac->module, search_req);
1041 static int objectclass_do_rename2(struct oc_context *ac);
1043 static int objectclass_do_rename(struct oc_context *ac)
1045 static const char * const attrs[] = { "objectClass", NULL };
1046 struct ldb_context *ldb;
1047 struct ldb_request *search_req;
1050 ldb = ldb_module_get_ctx(ac->module);
1052 /* Check if we have a valid parent - this check is needed since
1053 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1054 if (ac->search_res == NULL) {
1055 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1056 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1057 return LDB_ERR_OTHER;
1060 /* now assign "search_res2" to the parent entry to have "search_res"
1061 * free for another lookup */
1062 ac->search_res2 = ac->search_res;
1063 ac->search_res = NULL;
1065 /* this looks up the real existing object for fetching some important
1066 * information (objectclasses) */
1067 ret = ldb_build_search_req(&search_req, ldb,
1068 ac, ac->req->op.rename.olddn,
1072 ac, get_search_callback,
1074 LDB_REQ_SET_LOCATION(search_req);
1075 if (ret != LDB_SUCCESS) {
1079 ret = dsdb_request_add_controls(search_req,
1080 DSDB_FLAG_AS_SYSTEM |
1081 DSDB_SEARCH_SHOW_RECYCLED);
1082 if (ret != LDB_SUCCESS) {
1086 ac->step_fn = objectclass_do_rename2;
1088 return ldb_next_request(ac->module, search_req);
1091 static int objectclass_do_rename2(struct oc_context *ac)
1093 struct ldb_context *ldb;
1094 struct ldb_request *rename_req;
1095 struct ldb_dn *fixed_dn;
1098 ldb = ldb_module_get_ctx(ac->module);
1100 /* Check if we have a valid entry - this check is needed since
1101 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1102 if (ac->search_res == NULL) {
1103 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1104 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1105 return LDB_ERR_NO_SUCH_OBJECT;
1108 if (ac->schema != NULL) {
1109 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1110 const struct dsdb_class *objectclass;
1111 const char *rdn_name;
1112 bool allowed_class = false;
1116 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1118 if (oc_el_entry == NULL) {
1119 /* existing entry without a valid object class? */
1120 return ldb_operr(ldb);
1122 objectclass = dsdb_get_last_structural_class(ac->schema,
1124 if (objectclass == NULL) {
1125 /* existing entry without a valid object class? */
1126 return ldb_operr(ldb);
1129 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1130 if (rdn_name == NULL) {
1131 return ldb_operr(ldb);
1134 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1135 const struct dsdb_class *tmp_class =
1136 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1137 &oc_el_entry->values[i]);
1139 if (tmp_class == NULL) continue;
1141 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1145 ldb_asprintf_errstring(ldb,
1146 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1147 rdn_name, objectclass->lDAPDisplayName);
1148 return LDB_ERR_UNWILLING_TO_PERFORM;
1151 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1153 if (oc_el_parent == NULL) {
1154 /* existing entry without a valid object class? */
1155 return ldb_operr(ldb);
1158 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1159 const struct dsdb_class *sclass;
1161 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1162 &oc_el_parent->values[i]);
1164 /* We don't know this class? what is going on? */
1167 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1168 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1169 allowed_class = true;
1175 if (!allowed_class) {
1176 ldb_asprintf_errstring(ldb,
1177 "objectclass: structural objectClass %s is not a valid child class for %s",
1178 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1179 return LDB_ERR_NAMING_VIOLATION;
1183 /* Ensure we are not trying to rename it to be a child of itself */
1184 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1185 ac->req->op.rename.newdn) == 0) &&
1186 (ldb_dn_compare(ac->req->op.rename.olddn,
1187 ac->req->op.rename.newdn) != 0)) {
1188 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1189 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1190 return LDB_ERR_UNWILLING_TO_PERFORM;
1193 /* Fix up the DN to be in the standard form, taking
1194 * particular care to match the parent DN */
1195 ret = fix_dn(ldb, ac,
1196 ac->req->op.rename.newdn,
1197 ac->search_res2->message->dn,
1199 if (ret != LDB_SUCCESS) {
1200 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1201 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1206 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1207 ac->req->op.rename.olddn, fixed_dn,
1209 ac->req, dsdb_next_callback,
1211 LDB_REQ_SET_LOCATION(rename_req);
1212 if (ret != LDB_SUCCESS) {
1216 /* perform the rename */
1217 return ldb_next_request(ac->module, rename_req);
1220 static int objectclass_do_delete(struct oc_context *ac);
1222 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1224 static const char * const attrs[] = { "nCName", "objectClass",
1227 "isCriticalSystemObject", NULL };
1228 struct ldb_context *ldb;
1229 struct ldb_request *search_req;
1230 struct oc_context *ac;
1233 ldb = ldb_module_get_ctx(module);
1235 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1237 /* do not manipulate our control entries */
1238 if (ldb_dn_is_special(req->op.del.dn)) {
1239 return ldb_next_request(module, req);
1242 /* Bypass the constraint checks when we do have the "RELAX" control
1244 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1245 return ldb_next_request(module, req);
1248 ac = oc_init_context(module, req);
1250 return ldb_operr(ldb);
1253 /* this looks up the entry object for fetching some important
1254 * information (object classes, system flags...) */
1255 ret = ldb_build_search_req(&search_req, ldb,
1256 ac, req->op.del.dn, LDB_SCOPE_BASE,
1259 ac, get_search_callback,
1261 LDB_REQ_SET_LOCATION(search_req);
1262 if (ret != LDB_SUCCESS) {
1266 ret = dsdb_request_add_controls(search_req,
1267 DSDB_FLAG_AS_SYSTEM |
1268 DSDB_SEARCH_SHOW_RECYCLED);
1269 if (ret != LDB_SUCCESS) {
1273 ac->step_fn = objectclass_do_delete;
1275 return ldb_next_request(ac->module, search_req);
1278 static int objectclass_do_delete(struct oc_context *ac)
1280 struct ldb_context *ldb;
1282 int32_t systemFlags;
1283 bool isCriticalSystemObject;
1286 ldb = ldb_module_get_ctx(ac->module);
1288 /* Check if we have a valid entry - this check is needed since
1289 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1290 if (ac->search_res == NULL) {
1291 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1292 ldb_dn_get_linearized(ac->req->op.del.dn));
1293 return LDB_ERR_NO_SUCH_OBJECT;
1296 /* DC's ntDSDSA object */
1297 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb, ac)) == 0) {
1298 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1299 ldb_dn_get_linearized(ac->req->op.del.dn));
1300 return LDB_ERR_UNWILLING_TO_PERFORM;
1303 /* DC's rIDSet object */
1304 /* Perform this check only when it does exist - this is needed in order
1305 * to don't let existing provisions break, and to delete . */
1306 ret = samdb_rid_set_dn(ldb, ac, &dn);
1307 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_ATTRIBUTE)
1308 && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1309 ldb_asprintf_errstring(ldb, "objectclass: Unable to determine if %s, is this DC's rIDSet object: %s ",
1310 ldb_dn_get_linearized(ac->req->op.del.dn),
1311 ldb_errstring(ldb));
1314 if (ret == LDB_SUCCESS) {
1315 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1317 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1318 ldb_dn_get_linearized(ac->req->op.del.dn));
1319 return LDB_ERR_UNWILLING_TO_PERFORM;
1324 /* Only trusted request from system account are allowed to delete
1327 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1328 (ldb_req_is_untrusted(ac->req) ||
1329 !dsdb_module_am_system(ac->module))) {
1330 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1331 ldb_dn_get_linearized(ac->req->op.del.dn));
1332 return LDB_ERR_UNWILLING_TO_PERFORM;
1335 /* crossRef objects regarding config, schema and default domain NCs */
1336 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1337 "crossRef") != NULL) {
1338 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1340 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1341 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1344 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1345 ldb_dn_get_linearized(ac->req->op.del.dn));
1346 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1348 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1351 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1352 ldb_dn_get_linearized(ac->req->op.del.dn));
1353 return LDB_ERR_UNWILLING_TO_PERFORM;
1360 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1362 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1363 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1364 ldb_dn_get_linearized(ac->req->op.del.dn));
1365 return LDB_ERR_UNWILLING_TO_PERFORM;
1368 /* isCriticalSystemObject - but this only applies on tree delete
1369 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1370 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1371 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1372 "isCriticalSystemObject", false);
1373 if (isCriticalSystemObject) {
1375 * Following the explaination from Microsoft
1376 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1377 * "I finished the investigation on this behavior.
1378 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1379 * every object in the tree will be checked to see if it has isCriticalSystemObject
1380 * set to TRUE, including the root node on which the delete operation is performed
1381 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1382 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1383 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1384 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1387 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1388 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1389 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1390 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1391 ldb_asprintf_errstring(ldb,
1392 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1393 ldb_dn_get_linearized(ac->req->op.del.dn));
1394 return LDB_ERR_UNWILLING_TO_PERFORM;
1399 return ldb_next_request(ac->module, ac->req);
1402 static int objectclass_init(struct ldb_module *module)
1404 struct ldb_context *ldb = ldb_module_get_ctx(module);
1407 /* Init everything else */
1408 ret = ldb_next_init(module);
1409 if (ret != LDB_SUCCESS) {
1413 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1414 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1416 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1417 if (ret != LDB_SUCCESS) {
1418 ldb_debug(ldb, LDB_DEBUG_ERROR,
1419 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1420 return ldb_operr(ldb);
1426 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1427 .name = "objectclass",
1428 .add = objectclass_add,
1429 .modify = objectclass_modify,
1430 .rename = objectclass_rename,
1431 .del = objectclass_delete,
1432 .init_context = objectclass_init
1435 int ldb_objectclass_module_init(const char *version)
1437 LDB_MODULE_CHECK_VERSION(version);
1438 return ldb_register_module(&ldb_objectclass_module_ops);