s4-dsdb/objectclass: remove duplicated declaration for objectclass_do_add
[Samba.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blobbceeda91451e766e813c88d647ea14c6aad1c978
1 /*
2 ldb database library
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/>.
23 * Name: ldb
25 * Component: objectClass sorting and constraint checking module
27 * Description:
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
30 * valid parent),
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
38 #include "includes.h"
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"
49 struct oc_context {
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);
70 if (ac == NULL) {
71 ldb_oom(ldb);
72 return NULL;
75 ac->module = module;
76 ac->req = req;
77 ac->schema = dsdb_get_schema(ldb, ac);
79 return 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);
96 unsigned int i;
97 bool found;
99 if (schema == NULL) {
100 return LDB_SUCCESS;
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) {
113 continue;
116 found = false;
117 while (!found &&
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) {
122 found = true;
125 if (found) {
126 continue;
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;
136 return LDB_SUCCESS;
139 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
141 struct ldb_context *ldb;
142 struct oc_context *ac;
143 int ret;
145 ac = talloc_get_type(req->context, struct oc_context);
146 ldb = ldb_module_get_ctx(ac->module);
148 if (!ares) {
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");
164 talloc_free(ares);
165 return ldb_module_done(ac->req, NULL, NULL,
166 LDB_ERR_OPERATIONS_ERROR);
169 ac->search_res = talloc_steal(ac, ares);
170 break;
172 case LDB_REPLY_REFERRAL:
173 /* ignore */
174 talloc_free(ares);
175 break;
177 case LDB_REPLY_DONE:
178 talloc_free(ares);
179 ret = ac->step_fn(ac);
180 if (ret != LDB_SUCCESS) {
181 return ldb_module_done(ac->req, NULL, NULL, ret);
183 break;
186 return LDB_SUCCESS;
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,
202 TALLOC_CTX *mem_ctx,
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) {
213 return ldb_oom(ldb);
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) {
220 return ldb_oom(ldb);
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);
233 #if 0
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)));
241 #endif
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;
256 int ret;
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
269 * allowed. */
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,
274 "instanceType", 0);
275 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
276 char *referral_uri;
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);
283 if (val == NULL) {
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);
297 if (ac == NULL) {
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,
315 NULL,
316 ac, get_search_callback,
317 req);
318 LDB_REQ_SET_LOCATION(search_req);
319 if (ret != LDB_SUCCESS) {
320 return ret;
323 ret = dsdb_request_add_controls(search_req,
324 DSDB_FLAG_AS_SYSTEM |
325 DSDB_SEARCH_SHOW_RECYCLED);
326 if (ret != LDB_SUCCESS) {
327 return ret;
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) {
345 return false;
347 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
348 if (!rodc_control) {
349 return false;
352 rodc_control->critical = false;
353 return true;
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;
363 char *value;
364 const struct dsdb_class *objectclass;
365 struct ldb_dn *objectcategory;
366 int32_t systemFlags = 0;
367 unsigned int i, j;
368 bool found;
369 int ret;
371 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
372 if (msg == NULL) {
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
382 * isn't allowed. */
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);
393 } else {
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,
399 &msg->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));
403 return ret;
407 if (ac->schema != NULL) {
409 * Notice: by the normalization function call in "ldb_request()"
410 * case "LDB_ADD" we have always only *one* "objectClass"
411 * attribute at this stage!
414 objectclass_element = ldb_msg_find_element(msg, "objectClass");
415 if (!objectclass_element) {
416 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
417 ldb_dn_get_linearized(msg->dn));
418 return LDB_ERR_OBJECT_CLASS_VIOLATION;
420 if (objectclass_element->num_values == 0) {
421 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
422 ldb_dn_get_linearized(msg->dn));
423 return LDB_ERR_CONSTRAINT_VIOLATION;
426 /* Now do the sorting */
427 ret = dsdb_sort_objectClass_attr(ldb, ac->schema,
428 objectclass_element, msg,
429 objectclass_element);
430 if (ret != LDB_SUCCESS) {
431 return ret;
435 * Get the new top-most structural object class and check for
436 * unrelated structural classes
438 objectclass = dsdb_get_last_structural_class(ac->schema,
439 objectclass_element);
440 if (objectclass == NULL) {
441 ldb_asprintf_errstring(ldb,
442 "Failed to find a structural class for %s",
443 ldb_dn_get_linearized(msg->dn));
444 return LDB_ERR_UNWILLING_TO_PERFORM;
447 ret = check_unrelated_objectclasses(ac->module, ac->schema,
448 objectclass,
449 objectclass_element);
450 if (ret != LDB_SUCCESS) {
451 return ret;
454 rdn_name = ldb_dn_get_rdn_name(msg->dn);
455 if (rdn_name == NULL) {
456 return ldb_operr(ldb);
458 found = false;
459 for (i = 0; (!found) && (i < objectclass_element->num_values);
460 i++) {
461 const struct dsdb_class *tmp_class =
462 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
463 &objectclass_element->values[i]);
465 if (tmp_class == NULL) continue;
467 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
468 found = true;
470 if (!found) {
471 ldb_asprintf_errstring(ldb,
472 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
473 rdn_name, objectclass->lDAPDisplayName);
474 return LDB_ERR_NAMING_VIOLATION;
477 if (objectclass->systemOnly &&
478 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
479 !check_rodc_ntdsdsa_add(ac, objectclass)) {
480 ldb_asprintf_errstring(ldb,
481 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
482 objectclass->lDAPDisplayName,
483 ldb_dn_get_linearized(msg->dn));
484 return LDB_ERR_UNWILLING_TO_PERFORM;
487 if (ac->search_res && ac->search_res->message) {
488 struct ldb_message_element *oc_el
489 = ldb_msg_find_element(ac->search_res->message, "objectClass");
491 bool allowed_class = false;
492 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
493 const struct dsdb_class *sclass;
495 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
496 &oc_el->values[i]);
497 if (!sclass) {
498 /* We don't know this class? what is going on? */
499 continue;
501 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
502 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
503 allowed_class = true;
504 break;
509 if (!allowed_class) {
510 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
511 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
512 return LDB_ERR_NAMING_VIOLATION;
516 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
517 "objectCategory");
518 if (objectcategory == NULL) {
519 struct dsdb_extended_dn_store_format *dn_format =
520 talloc_get_type(ldb_module_get_private(ac->module),
521 struct dsdb_extended_dn_store_format);
522 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
523 /* Strip off extended components */
524 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
525 objectclass->defaultObjectCategory);
526 value = ldb_dn_alloc_linearized(msg, dn);
527 talloc_free(dn);
528 } else {
529 value = talloc_strdup(msg,
530 objectclass->defaultObjectCategory);
532 if (value == NULL) {
533 return ldb_module_oom(ac->module);
536 ret = ldb_msg_add_string(msg, "objectCategory", value);
537 if (ret != LDB_SUCCESS) {
538 return ret;
540 } else {
541 const struct dsdb_class *ocClass =
542 dsdb_class_by_cn_ldb_val(ac->schema,
543 ldb_dn_get_rdn_val(objectcategory));
544 if (ocClass != NULL) {
545 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
546 ocClass->defaultObjectCategory);
547 if (ldb_dn_compare(objectcategory, dn) != 0) {
548 ocClass = NULL;
551 talloc_free(objectcategory);
552 if (ocClass == NULL) {
553 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
554 ldb_dn_get_linearized(msg->dn));
555 return LDB_ERR_OBJECT_CLASS_VIOLATION;
559 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
560 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
561 "TRUE");
564 /* There are very special rules for systemFlags, see MS-ADTS
565 * MS-ADTS 3.1.1.5.2.4 */
567 el = ldb_msg_find_element(msg, "systemFlags");
568 if ((el != NULL) && (el->num_values > 1)) {
569 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
570 ldb_dn_get_linearized(msg->dn));
571 return LDB_ERR_CONSTRAINT_VIOLATION;
574 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
576 ldb_msg_remove_attr(msg, "systemFlags");
578 /* Only the following flags may be set by a client */
579 if (ldb_request_get_control(ac->req,
580 LDB_CONTROL_RELAX_OID) == NULL) {
581 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
582 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
583 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
584 | SYSTEM_FLAG_ATTR_IS_RDN );
587 /* But the last one ("ATTR_IS_RDN") is only allowed on
588 * "attributeSchema" objects. So truncate if it does not fit. */
589 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
590 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
593 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
594 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
595 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
596 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
597 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
598 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
599 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
600 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
601 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
602 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
603 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
604 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
605 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
607 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
609 if (el || systemFlags != 0) {
610 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
611 systemFlags);
612 if (ret != LDB_SUCCESS) {
613 return ret;
617 /* make sure that "isCriticalSystemObject" is not specified! */
618 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
619 if ((el != NULL) &&
620 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
621 ldb_set_errstring(ldb,
622 "objectclass: 'isCriticalSystemObject' must not be specified!");
623 return LDB_ERR_UNWILLING_TO_PERFORM;
627 ret = ldb_build_add_req(&add_req, ldb, ac,
628 msg,
629 ac->req->controls,
630 ac->req, dsdb_next_callback,
631 ac->req);
632 LDB_REQ_SET_LOCATION(add_req);
633 if (ret != LDB_SUCCESS) {
634 return ret;
637 /* perform the add */
638 return ldb_next_request(ac->module, add_req);
641 static int oc_modify_callback(struct ldb_request *req,
642 struct ldb_reply *ares);
643 static int objectclass_do_mod(struct oc_context *ac);
645 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
647 struct ldb_context *ldb = ldb_module_get_ctx(module);
648 struct ldb_message_element *objectclass_element;
649 struct ldb_message *msg;
650 struct ldb_request *down_req;
651 struct oc_context *ac;
652 bool oc_changes = false;
653 int ret;
655 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
657 /* do not manipulate our control entries */
658 if (ldb_dn_is_special(req->op.mod.message->dn)) {
659 return ldb_next_request(module, req);
662 /* As with the "real" AD we don't accept empty messages */
663 if (req->op.mod.message->num_elements == 0) {
664 ldb_set_errstring(ldb, "objectclass: modify message must have "
665 "elements/attributes!");
666 return LDB_ERR_UNWILLING_TO_PERFORM;
669 ac = oc_init_context(module, req);
670 if (ac == NULL) {
671 return ldb_operr(ldb);
674 /* Without schema, there isn't much to do here */
675 if (ac->schema == NULL) {
676 talloc_free(ac);
677 return ldb_next_request(module, req);
680 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
681 if (msg == NULL) {
682 return ldb_module_oom(ac->module);
685 /* For now change everything except the objectclasses */
687 objectclass_element = ldb_msg_find_element(msg, "objectClass");
688 if (objectclass_element != NULL) {
689 ldb_msg_remove_attr(msg, "objectClass");
690 oc_changes = true;
693 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
694 * only on application NCs - not on the default ones */
695 if (oc_changes &&
696 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
697 struct ldb_dn *nc_root;
699 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
700 &nc_root);
701 if (ret != LDB_SUCCESS) {
702 return ret;
705 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
706 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
707 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
708 ldb_set_errstring(ldb,
709 "objectclass: object class changes on objects under the standard name contexts not allowed!");
710 return LDB_ERR_UNWILLING_TO_PERFORM;
713 talloc_free(nc_root);
716 if (oc_changes) {
717 ret = ldb_build_mod_req(&down_req, ldb, ac,
718 msg,
719 req->controls, ac,
720 oc_modify_callback,
721 req);
722 } else {
723 ret = ldb_build_mod_req(&down_req, ldb, ac,
724 msg,
725 req->controls, req,
726 dsdb_next_callback,
727 req);
729 LDB_REQ_SET_LOCATION(down_req);
730 if (ret != LDB_SUCCESS) {
731 return ret;
734 return ldb_next_request(module, down_req);
737 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
739 static const char * const attrs[] = { "objectClass", NULL };
740 struct ldb_context *ldb;
741 struct ldb_request *search_req;
742 struct oc_context *ac;
743 int ret;
745 ac = talloc_get_type(req->context, struct oc_context);
746 ldb = ldb_module_get_ctx(ac->module);
748 if (!ares) {
749 return ldb_module_done(ac->req, NULL, NULL,
750 LDB_ERR_OPERATIONS_ERROR);
753 if (ares->type == LDB_REPLY_REFERRAL) {
754 return ldb_module_send_referral(ac->req, ares->referral);
757 if (ares->error != LDB_SUCCESS) {
758 return ldb_module_done(ac->req, ares->controls,
759 ares->response, ares->error);
762 if (ares->type != LDB_REPLY_DONE) {
763 talloc_free(ares);
764 return ldb_module_done(ac->req, NULL, NULL,
765 LDB_ERR_OPERATIONS_ERROR);
768 talloc_free(ares);
770 /* this looks up the real existing object for fetching some important
771 * information (objectclasses) */
772 ret = ldb_build_search_req(&search_req, ldb,
773 ac, ac->req->op.mod.message->dn,
774 LDB_SCOPE_BASE,
775 "(objectClass=*)",
776 attrs, NULL,
777 ac, get_search_callback,
778 ac->req);
779 LDB_REQ_SET_LOCATION(search_req);
780 if (ret != LDB_SUCCESS) {
781 return ldb_module_done(ac->req, NULL, NULL, ret);
784 ret = dsdb_request_add_controls(search_req,
785 DSDB_FLAG_AS_SYSTEM |
786 DSDB_SEARCH_SHOW_RECYCLED);
787 if (ret != LDB_SUCCESS) {
788 return ldb_module_done(ac->req, NULL, NULL, ret);
791 ac->step_fn = objectclass_do_mod;
793 ret = ldb_next_request(ac->module, search_req);
794 if (ret != LDB_SUCCESS) {
795 return ldb_module_done(ac->req, NULL, NULL, ret);
798 return LDB_SUCCESS;
801 static int objectclass_do_mod(struct oc_context *ac)
803 struct ldb_context *ldb;
804 struct ldb_request *mod_req;
805 struct ldb_message_element *oc_el_entry, *oc_el_change;
806 struct ldb_val *vals;
807 struct ldb_message *msg;
808 const struct dsdb_class *objectclass;
809 unsigned int i, j, k;
810 bool found;
811 int ret;
813 ldb = ldb_module_get_ctx(ac->module);
815 /* we should always have a valid entry when we enter here */
816 if (ac->search_res == NULL) {
817 return ldb_operr(ldb);
820 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
821 "objectClass");
822 if (oc_el_entry == NULL) {
823 /* existing entry without a valid object class? */
824 return ldb_operr(ldb);
827 /* use a new message structure */
828 msg = ldb_msg_new(ac);
829 if (msg == NULL) {
830 return ldb_module_oom(ac->module);
833 msg->dn = ac->req->op.mod.message->dn;
835 /* We've to walk over all "objectClass" message elements */
836 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
837 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
838 "objectClass") != 0) {
839 continue;
842 oc_el_change = &ac->req->op.mod.message->elements[k];
844 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
845 case LDB_FLAG_MOD_ADD:
846 /* Merge the two message elements */
847 for (i = 0; i < oc_el_change->num_values; i++) {
848 for (j = 0; j < oc_el_entry->num_values; j++) {
849 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
850 (char *)oc_el_entry->values[j].data) == 0) {
851 ldb_asprintf_errstring(ldb,
852 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
853 (int)oc_el_change->values[i].length,
854 (const char *)oc_el_change->values[i].data);
855 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
858 /* append the new object class value - code was
859 * copied from "ldb_msg_add_value" */
860 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
861 struct ldb_val,
862 oc_el_entry->num_values + 1);
863 if (vals == NULL) {
864 return ldb_module_oom(ac->module);
866 oc_el_entry->values = vals;
867 oc_el_entry->values[oc_el_entry->num_values] =
868 oc_el_change->values[i];
869 ++(oc_el_entry->num_values);
872 break;
874 case LDB_FLAG_MOD_REPLACE:
876 * In this case the new "oc_el_entry" is simply
877 * "oc_el_change"
879 oc_el_entry = oc_el_change;
881 break;
883 case LDB_FLAG_MOD_DELETE:
884 /* Merge the two message elements */
885 for (i = 0; i < oc_el_change->num_values; i++) {
886 found = false;
887 for (j = 0; j < oc_el_entry->num_values; j++) {
888 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
889 (char *)oc_el_entry->values[j].data) == 0) {
890 found = true;
891 /* delete the object class value
892 * - code was copied from
893 * "ldb_msg_remove_element" */
894 if (j != oc_el_entry->num_values - 1) {
895 memmove(&oc_el_entry->values[j],
896 &oc_el_entry->values[j+1],
897 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
899 --(oc_el_entry->num_values);
900 break;
903 if (!found) {
904 /* we cannot delete a not existing
905 * object class */
906 ldb_asprintf_errstring(ldb,
907 "objectclass: cannot delete this objectclass: '%.*s'!",
908 (int)oc_el_change->values[i].length,
909 (const char *)oc_el_change->values[i].data);
910 return LDB_ERR_NO_SUCH_ATTRIBUTE;
914 break;
917 /* Now do the sorting */
918 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, oc_el_entry,
919 msg, oc_el_entry);
920 if (ret != LDB_SUCCESS) {
921 return ret;
925 * Get the new top-most structural object class and check for
926 * unrelated structural classes
928 objectclass = dsdb_get_last_structural_class(ac->schema,
929 oc_el_entry);
930 if (objectclass == NULL) {
931 ldb_set_errstring(ldb,
932 "objectclass: cannot delete all structural objectclasses!");
933 return LDB_ERR_OBJECT_CLASS_VIOLATION;
936 /* Check for unrelated objectclasses */
937 ret = check_unrelated_objectclasses(ac->module, ac->schema,
938 objectclass,
939 oc_el_entry);
940 if (ret != LDB_SUCCESS) {
941 return ret;
945 /* Now add the new object class attribute to the change message */
946 ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
947 if (ret != LDB_SUCCESS) {
948 ldb_module_oom(ac->module);
949 return ret;
952 /* Now we have the real and definitive change left to do */
954 ret = ldb_build_mod_req(&mod_req, ldb, ac,
955 msg,
956 ac->req->controls,
957 ac->req, dsdb_next_callback,
958 ac->req);
959 LDB_REQ_SET_LOCATION(mod_req);
960 if (ret != LDB_SUCCESS) {
961 return ret;
964 return ldb_next_request(ac->module, mod_req);
967 static int objectclass_do_rename(struct oc_context *ac);
969 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
971 static const char * const attrs[] = { "objectClass", NULL };
972 struct ldb_context *ldb;
973 struct ldb_request *search_req;
974 struct oc_context *ac;
975 struct ldb_dn *parent_dn;
976 int ret;
978 ldb = ldb_module_get_ctx(module);
980 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
982 /* do not manipulate our control entries */
983 if (ldb_dn_is_special(req->op.rename.olddn)) {
984 return ldb_next_request(module, req);
987 ac = oc_init_context(module, req);
988 if (ac == NULL) {
989 return ldb_operr(ldb);
992 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
993 if (parent_dn == NULL) {
994 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
995 ldb_dn_get_linearized(req->op.rename.olddn));
996 return LDB_ERR_NO_SUCH_OBJECT;
999 /* this looks up the parent object for fetching some important
1000 * information (objectclasses, DN normalisation...) */
1001 ret = ldb_build_search_req(&search_req, ldb,
1002 ac, parent_dn, LDB_SCOPE_BASE,
1003 "(objectClass=*)",
1004 attrs, NULL,
1005 ac, get_search_callback,
1006 req);
1007 LDB_REQ_SET_LOCATION(search_req);
1008 if (ret != LDB_SUCCESS) {
1009 return ret;
1012 /* we have to add the show recycled control, as otherwise DRS
1013 deletes will be refused as we will think the target parent
1014 does not exist */
1015 ret = dsdb_request_add_controls(search_req,
1016 DSDB_FLAG_AS_SYSTEM |
1017 DSDB_SEARCH_SHOW_RECYCLED);
1018 if (ret != LDB_SUCCESS) {
1019 return ret;
1022 ac->step_fn = objectclass_do_rename;
1024 return ldb_next_request(ac->module, search_req);
1027 static int objectclass_do_rename2(struct oc_context *ac);
1029 static int objectclass_do_rename(struct oc_context *ac)
1031 static const char * const attrs[] = { "objectClass", NULL };
1032 struct ldb_context *ldb;
1033 struct ldb_request *search_req;
1034 int ret;
1036 ldb = ldb_module_get_ctx(ac->module);
1038 /* Check if we have a valid parent - this check is needed since
1039 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1040 if (ac->search_res == NULL) {
1041 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1042 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1043 return LDB_ERR_OTHER;
1046 /* now assign "search_res2" to the parent entry to have "search_res"
1047 * free for another lookup */
1048 ac->search_res2 = ac->search_res;
1049 ac->search_res = NULL;
1051 /* this looks up the real existing object for fetching some important
1052 * information (objectclasses) */
1053 ret = ldb_build_search_req(&search_req, ldb,
1054 ac, ac->req->op.rename.olddn,
1055 LDB_SCOPE_BASE,
1056 "(objectClass=*)",
1057 attrs, NULL,
1058 ac, get_search_callback,
1059 ac->req);
1060 LDB_REQ_SET_LOCATION(search_req);
1061 if (ret != LDB_SUCCESS) {
1062 return ret;
1065 ret = dsdb_request_add_controls(search_req,
1066 DSDB_FLAG_AS_SYSTEM |
1067 DSDB_SEARCH_SHOW_RECYCLED);
1068 if (ret != LDB_SUCCESS) {
1069 return ret;
1072 ac->step_fn = objectclass_do_rename2;
1074 return ldb_next_request(ac->module, search_req);
1077 static int objectclass_do_rename2(struct oc_context *ac)
1079 struct ldb_context *ldb;
1080 struct ldb_request *rename_req;
1081 struct ldb_dn *fixed_dn;
1082 int ret;
1084 ldb = ldb_module_get_ctx(ac->module);
1086 /* Check if we have a valid entry - this check is needed since
1087 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1088 if (ac->search_res == NULL) {
1089 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1090 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1091 return LDB_ERR_NO_SUCH_OBJECT;
1094 if (ac->schema != NULL) {
1095 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1096 const struct dsdb_class *objectclass;
1097 const char *rdn_name;
1098 bool allowed_class = false;
1099 unsigned int i, j;
1100 bool found;
1102 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1103 "objectClass");
1104 if (oc_el_entry == NULL) {
1105 /* existing entry without a valid object class? */
1106 return ldb_operr(ldb);
1108 objectclass = dsdb_get_last_structural_class(ac->schema,
1109 oc_el_entry);
1110 if (objectclass == NULL) {
1111 /* existing entry without a valid object class? */
1112 return ldb_operr(ldb);
1115 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1116 if (rdn_name == NULL) {
1117 return ldb_operr(ldb);
1119 found = false;
1120 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1121 const struct dsdb_class *tmp_class =
1122 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1123 &oc_el_entry->values[i]);
1125 if (tmp_class == NULL) continue;
1127 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1128 found = true;
1130 if (!found) {
1131 ldb_asprintf_errstring(ldb,
1132 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1133 rdn_name, objectclass->lDAPDisplayName);
1134 return LDB_ERR_UNWILLING_TO_PERFORM;
1137 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1138 "objectClass");
1139 if (oc_el_parent == NULL) {
1140 /* existing entry without a valid object class? */
1141 return ldb_operr(ldb);
1144 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1145 const struct dsdb_class *sclass;
1147 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1148 &oc_el_parent->values[i]);
1149 if (!sclass) {
1150 /* We don't know this class? what is going on? */
1151 continue;
1153 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1154 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1155 allowed_class = true;
1156 break;
1161 if (!allowed_class) {
1162 ldb_asprintf_errstring(ldb,
1163 "objectclass: structural objectClass %s is not a valid child class for %s",
1164 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1165 return LDB_ERR_NAMING_VIOLATION;
1169 /* Ensure we are not trying to rename it to be a child of itself */
1170 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1171 ac->req->op.rename.newdn) == 0) &&
1172 (ldb_dn_compare(ac->req->op.rename.olddn,
1173 ac->req->op.rename.newdn) != 0)) {
1174 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1175 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1176 return LDB_ERR_UNWILLING_TO_PERFORM;
1179 /* Fix up the DN to be in the standard form, taking
1180 * particular care to match the parent DN */
1181 ret = fix_dn(ldb, ac,
1182 ac->req->op.rename.newdn,
1183 ac->search_res2->message->dn,
1184 &fixed_dn);
1185 if (ret != LDB_SUCCESS) {
1186 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1187 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1188 return ret;
1192 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1193 ac->req->op.rename.olddn, fixed_dn,
1194 ac->req->controls,
1195 ac->req, dsdb_next_callback,
1196 ac->req);
1197 LDB_REQ_SET_LOCATION(rename_req);
1198 if (ret != LDB_SUCCESS) {
1199 return ret;
1202 /* perform the rename */
1203 return ldb_next_request(ac->module, rename_req);
1206 static int objectclass_do_delete(struct oc_context *ac);
1208 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1210 static const char * const attrs[] = { "nCName", "objectClass",
1211 "systemFlags",
1212 "isDeleted",
1213 "isCriticalSystemObject", NULL };
1214 struct ldb_context *ldb;
1215 struct ldb_request *search_req;
1216 struct oc_context *ac;
1217 int ret;
1219 ldb = ldb_module_get_ctx(module);
1221 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1223 /* do not manipulate our control entries */
1224 if (ldb_dn_is_special(req->op.del.dn)) {
1225 return ldb_next_request(module, req);
1228 /* Bypass the constraint checks when we do have the "RELAX" control
1229 * set. */
1230 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1231 return ldb_next_request(module, req);
1234 ac = oc_init_context(module, req);
1235 if (ac == NULL) {
1236 return ldb_operr(ldb);
1239 /* this looks up the entry object for fetching some important
1240 * information (object classes, system flags...) */
1241 ret = ldb_build_search_req(&search_req, ldb,
1242 ac, req->op.del.dn, LDB_SCOPE_BASE,
1243 "(objectClass=*)",
1244 attrs, NULL,
1245 ac, get_search_callback,
1246 req);
1247 LDB_REQ_SET_LOCATION(search_req);
1248 if (ret != LDB_SUCCESS) {
1249 return ret;
1252 ret = dsdb_request_add_controls(search_req,
1253 DSDB_FLAG_AS_SYSTEM |
1254 DSDB_SEARCH_SHOW_RECYCLED);
1255 if (ret != LDB_SUCCESS) {
1256 return ret;
1259 ac->step_fn = objectclass_do_delete;
1261 return ldb_next_request(ac->module, search_req);
1264 static int objectclass_do_delete(struct oc_context *ac)
1266 struct ldb_context *ldb;
1267 struct ldb_dn *dn;
1268 int32_t systemFlags;
1269 bool isCriticalSystemObject;
1270 int ret;
1272 ldb = ldb_module_get_ctx(ac->module);
1274 /* Check if we have a valid entry - this check is needed since
1275 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1276 if (ac->search_res == NULL) {
1277 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1278 ldb_dn_get_linearized(ac->req->op.del.dn));
1279 return LDB_ERR_NO_SUCH_OBJECT;
1282 /* DC's ntDSDSA object */
1283 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb, ac)) == 0) {
1284 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1285 ldb_dn_get_linearized(ac->req->op.del.dn));
1286 return LDB_ERR_UNWILLING_TO_PERFORM;
1289 /* DC's rIDSet object */
1290 /* Perform this check only when it does exist - this is needed in order
1291 * to don't let existing provisions break. */
1292 ret = samdb_rid_set_dn(ldb, ac, &dn);
1293 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1294 return ret;
1296 if (ret == LDB_SUCCESS) {
1297 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1298 talloc_free(dn);
1299 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1300 ldb_dn_get_linearized(ac->req->op.del.dn));
1301 return LDB_ERR_UNWILLING_TO_PERFORM;
1303 talloc_free(dn);
1306 /* Only trusted request from system account are allowed to delete
1307 * deleted objects.
1309 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1310 (ldb_req_is_untrusted(ac->req) ||
1311 !dsdb_module_am_system(ac->module))) {
1312 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1313 ldb_dn_get_linearized(ac->req->op.del.dn));
1314 return LDB_ERR_UNWILLING_TO_PERFORM;
1317 /* crossRef objects regarding config, schema and default domain NCs */
1318 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1319 "crossRef") != NULL) {
1320 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1321 "nCName");
1322 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1323 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1324 talloc_free(dn);
1326 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1327 ldb_dn_get_linearized(ac->req->op.del.dn));
1328 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1330 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1331 talloc_free(dn);
1333 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1334 ldb_dn_get_linearized(ac->req->op.del.dn));
1335 return LDB_ERR_UNWILLING_TO_PERFORM;
1337 talloc_free(dn);
1340 /* systemFlags */
1342 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1343 "systemFlags", 0);
1344 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1345 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1346 ldb_dn_get_linearized(ac->req->op.del.dn));
1347 return LDB_ERR_UNWILLING_TO_PERFORM;
1350 /* isCriticalSystemObject - but this only applies on tree delete
1351 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1352 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1353 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1354 "isCriticalSystemObject", false);
1355 if (isCriticalSystemObject) {
1357 * Following the explaination from Microsoft
1358 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1359 * "I finished the investigation on this behavior.
1360 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1361 * every object in the tree will be checked to see if it has isCriticalSystemObject
1362 * set to TRUE, including the root node on which the delete operation is performed
1363 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1364 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1365 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1366 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1369 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1370 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1371 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1372 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1373 ldb_asprintf_errstring(ldb,
1374 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1375 ldb_dn_get_linearized(ac->req->op.del.dn));
1376 return LDB_ERR_UNWILLING_TO_PERFORM;
1381 return ldb_next_request(ac->module, ac->req);
1384 static int objectclass_init(struct ldb_module *module)
1386 struct ldb_context *ldb = ldb_module_get_ctx(module);
1387 int ret;
1389 /* Init everything else */
1390 ret = ldb_next_init(module);
1391 if (ret != LDB_SUCCESS) {
1392 return ret;
1395 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1396 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1398 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1399 if (ret != LDB_SUCCESS) {
1400 ldb_debug(ldb, LDB_DEBUG_ERROR,
1401 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1402 return ldb_operr(ldb);
1405 return ret;
1408 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1409 .name = "objectclass",
1410 .add = objectclass_add,
1411 .modify = objectclass_modify,
1412 .rename = objectclass_rename,
1413 .del = objectclass_delete,
1414 .init_context = objectclass_init
1417 int ldb_objectclass_module_init(const char *version)
1419 LDB_MODULE_CHECK_VERSION(version);
1420 return ldb_register_module(&ldb_objectclass_module_ops);