s4:dsdb - introduce a only constant-time "get_last_structural_class()" call
[Samba/id10ts.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blob033330c86c2859ff78789c2d6640ddd64b57a72c
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/schema.h"
48 #include "dsdb/samdb/ldb_modules/util.h"
50 struct oc_context {
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 *);
62 static struct oc_context *oc_init_context(struct ldb_module *module,
63 struct ldb_request *req)
65 struct ldb_context *ldb;
66 struct oc_context *ac;
68 ldb = ldb_module_get_ctx(module);
70 ac = talloc_zero(req, struct oc_context);
71 if (ac == NULL) {
72 ldb_oom(ldb);
73 return NULL;
76 ac->module = module;
77 ac->req = req;
78 ac->schema = dsdb_get_schema(ldb, ac);
80 return ac;
83 static int objectclass_do_add(struct oc_context *ac);
86 * This checks if we have unrelated object classes in our entry's "objectClass"
87 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
88 * or two or more disjunct structural ones.
89 * If one of these conditions are true, blame.
91 static int check_unrelated_objectclasses(struct ldb_module *module,
92 const struct dsdb_schema *schema,
93 const struct dsdb_class *struct_objectclass,
94 struct ldb_message_element *objectclass_element)
96 struct ldb_context *ldb = ldb_module_get_ctx(module);
97 unsigned int i;
98 bool found;
100 if (schema == NULL) {
101 return LDB_SUCCESS;
104 for (i = 0; i < objectclass_element->num_values; i++) {
105 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
106 &objectclass_element->values[i]);
107 const struct dsdb_class *tmp_class2 = struct_objectclass;
109 /* Pointer comparison can be used due to the same schema str. */
110 if (tmp_class == NULL ||
111 tmp_class == struct_objectclass ||
112 tmp_class->objectClassCategory > 2 ||
113 ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
114 continue;
117 found = false;
118 while (!found &&
119 ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
120 tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
121 tmp_class2->subClassOf);
122 if (tmp_class2 == tmp_class) {
123 found = true;
126 if (found) {
127 continue;
130 ldb_asprintf_errstring(ldb,
131 "objectclass: the objectclass '%s' seems to be unrelated to the entry!",
132 tmp_class->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 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
191 struct oc_context *ac;
193 ac = talloc_get_type(req->context, struct oc_context);
195 if (!ares) {
196 return ldb_module_done(ac->req, NULL, NULL,
197 LDB_ERR_OPERATIONS_ERROR);
200 if (ares->type == LDB_REPLY_REFERRAL) {
201 return ldb_module_send_referral(ac->req, ares->referral);
204 if (ares->error != LDB_SUCCESS) {
205 return ldb_module_done(ac->req, ares->controls,
206 ares->response, ares->error);
209 if (ares->type != LDB_REPLY_DONE) {
210 talloc_free(ares);
211 return ldb_module_done(ac->req, NULL, NULL,
212 LDB_ERR_OPERATIONS_ERROR);
215 return ldb_module_done(ac->req, ares->controls,
216 ares->response, ares->error);
219 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
221 This should mean that if the parent is:
222 CN=Users,DC=samba,DC=example,DC=com
223 and a proposed child is
224 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
226 The resulting DN should be:
228 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
231 static int fix_dn(struct ldb_context *ldb,
232 TALLOC_CTX *mem_ctx,
233 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
234 struct ldb_dn **fixed_dn)
236 char *upper_rdn_attr;
237 const struct ldb_val *rdn_val;
239 /* Fix up the DN to be in the standard form, taking particular care to
240 * match the parent DN */
241 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
242 if (*fixed_dn == NULL) {
243 return ldb_oom(ldb);
246 /* We need the attribute name in upper case */
247 upper_rdn_attr = strupper_talloc(*fixed_dn,
248 ldb_dn_get_rdn_name(newdn));
249 if (upper_rdn_attr == NULL) {
250 return ldb_oom(ldb);
253 /* Create a new child */
254 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
255 return ldb_operr(ldb);
258 rdn_val = ldb_dn_get_rdn_val(newdn);
259 if (rdn_val == NULL) {
260 return ldb_operr(ldb);
263 #if 0
264 /* the rules for rDN length constraints are more complex than
265 this. Until we understand them we need to leave this
266 constraint out. Otherwise we break replication, as windows
267 does sometimes send us rDNs longer than 64 */
268 if (!rdn_val || rdn_val->length > 64) {
269 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
271 #endif
274 /* And replace it with CN=foo (we need the attribute in upper case) */
275 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
279 static int objectclass_do_add(struct oc_context *ac);
281 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
283 struct ldb_context *ldb;
284 struct ldb_request *search_req;
285 struct oc_context *ac;
286 struct ldb_dn *parent_dn;
287 const struct ldb_val *val;
288 int ret;
289 static const char * const parent_attrs[] = { "objectClass", NULL };
291 ldb = ldb_module_get_ctx(module);
293 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
295 /* do not manipulate our control entries */
296 if (ldb_dn_is_special(req->op.add.message->dn)) {
297 return ldb_next_request(module, req);
300 /* An add operation on the basedn without "NC-add" operation isn't
301 * allowed. */
302 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
303 unsigned int instanceType;
305 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
306 "instanceType", 0);
307 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
308 char *referral_uri;
309 /* When we are trying to readd the root basedn then
310 * this is denied, but with an interesting mechanism:
311 * there is generated a referral with the last
312 * component value as hostname. */
313 val = ldb_dn_get_component_val(req->op.add.message->dn,
314 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
315 if (val == NULL) {
316 return ldb_operr(ldb);
318 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
319 ldb_dn_get_linearized(req->op.add.message->dn));
320 if (referral_uri == NULL) {
321 return ldb_module_oom(module);
324 return ldb_module_send_referral(req, referral_uri);
328 ac = oc_init_context(module, req);
329 if (ac == NULL) {
330 return ldb_operr(ldb);
333 /* If there isn't a parent, just go on to the add processing */
334 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
335 return objectclass_do_add(ac);
338 /* get copy of parent DN */
339 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
340 if (parent_dn == NULL) {
341 return ldb_operr(ldb);
344 ret = ldb_build_search_req(&search_req, ldb,
345 ac, parent_dn, LDB_SCOPE_BASE,
346 "(objectClass=*)", parent_attrs,
347 NULL,
348 ac, get_search_callback,
349 req);
350 LDB_REQ_SET_LOCATION(search_req);
351 if (ret != LDB_SUCCESS) {
352 return ret;
355 ac->step_fn = objectclass_do_add;
357 return ldb_next_request(ac->module, search_req);
362 check if this is a special RODC nTDSDSA add
364 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
365 const struct dsdb_class *objectclass)
367 struct ldb_control *rodc_control;
369 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
370 return false;
372 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
373 if (!rodc_control) {
374 return false;
377 rodc_control->critical = false;
378 return true;
381 static int objectclass_do_add(struct oc_context *ac)
383 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
384 struct ldb_request *add_req;
385 struct ldb_message_element *objectclass_element, *el;
386 struct ldb_message *msg;
387 TALLOC_CTX *mem_ctx;
388 const char *rdn_name = NULL;
389 char *value;
390 const struct dsdb_class *objectclass;
391 struct ldb_dn *objectcategory;
392 int32_t systemFlags = 0;
393 unsigned int i, j;
394 bool found;
395 int ret;
397 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
398 if (msg == NULL) {
399 return ldb_module_oom(ac->module);
402 /* Check if we have a valid parent - this check is needed since
403 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
404 if (ac->search_res == NULL) {
405 unsigned int instanceType;
407 /* An add operation on partition DNs without "NC-add" operation
408 * isn't allowed. */
409 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
411 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
412 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
413 ldb_dn_get_linearized(msg->dn));
414 return LDB_ERR_NO_SUCH_OBJECT;
417 /* Don't keep any error messages - we've to add a partition */
418 ldb_set_errstring(ldb, NULL);
419 } else {
420 /* Fix up the DN to be in the standard form, taking
421 * particular care to match the parent DN */
422 ret = fix_dn(ldb, msg,
423 ac->req->op.add.message->dn,
424 ac->search_res->message->dn,
425 &msg->dn);
426 if (ret != LDB_SUCCESS) {
427 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
428 ldb_dn_get_linearized(ac->req->op.add.message->dn));
429 return ret;
433 if (ac->schema != NULL) {
435 * Notice: by the normalization function call in "ldb_request()"
436 * case "LDB_ADD" we have always only *one* "objectClass"
437 * attribute at this stage!
440 objectclass_element = ldb_msg_find_element(msg, "objectClass");
441 if (!objectclass_element) {
442 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
443 ldb_dn_get_linearized(msg->dn));
444 return LDB_ERR_OBJECT_CLASS_VIOLATION;
446 if (objectclass_element->num_values == 0) {
447 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
448 ldb_dn_get_linearized(msg->dn));
449 return LDB_ERR_CONSTRAINT_VIOLATION;
452 mem_ctx = talloc_new(ac);
453 if (mem_ctx == NULL) {
454 return ldb_module_oom(ac->module);
457 /* Now do the sorting */
458 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, mem_ctx,
459 objectclass_element, msg,
460 objectclass_element);
461 if (ret != LDB_SUCCESS) {
462 talloc_free(mem_ctx);
463 return ret;
466 talloc_free(mem_ctx);
469 * Get the new top-most structural object class and check for
470 * unrelated structural classes
472 objectclass = get_last_structural_class(ac->schema,
473 objectclass_element);
474 if (objectclass == NULL) {
475 ldb_asprintf_errstring(ldb,
476 "Failed to find a structural class for %s",
477 ldb_dn_get_linearized(msg->dn));
478 return LDB_ERR_UNWILLING_TO_PERFORM;
481 ret = check_unrelated_objectclasses(ac->module, ac->schema,
482 objectclass,
483 objectclass_element);
484 if (ret != LDB_SUCCESS) {
485 return ret;
488 rdn_name = ldb_dn_get_rdn_name(msg->dn);
489 if (rdn_name == NULL) {
490 return ldb_operr(ldb);
492 found = false;
493 for (i = 0; (!found) && (i < objectclass_element->num_values);
494 i++) {
495 const struct dsdb_class *tmp_class =
496 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
497 &objectclass_element->values[i]);
499 if (tmp_class == NULL) continue;
501 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
502 found = true;
504 if (!found) {
505 ldb_asprintf_errstring(ldb,
506 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
507 rdn_name, objectclass->lDAPDisplayName);
508 return LDB_ERR_NAMING_VIOLATION;
511 if (objectclass->systemOnly &&
512 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
513 !check_rodc_ntdsdsa_add(ac, objectclass)) {
514 ldb_asprintf_errstring(ldb,
515 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
516 objectclass->lDAPDisplayName,
517 ldb_dn_get_linearized(msg->dn));
518 return LDB_ERR_UNWILLING_TO_PERFORM;
521 if (ac->search_res && ac->search_res->message) {
522 struct ldb_message_element *oc_el
523 = ldb_msg_find_element(ac->search_res->message, "objectClass");
525 bool allowed_class = false;
526 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
527 const struct dsdb_class *sclass;
529 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
530 &oc_el->values[i]);
531 if (!sclass) {
532 /* We don't know this class? what is going on? */
533 continue;
535 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
536 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
537 allowed_class = true;
538 break;
543 if (!allowed_class) {
544 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
545 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
546 return LDB_ERR_NAMING_VIOLATION;
550 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
551 "objectCategory");
552 if (objectcategory == NULL) {
553 struct dsdb_extended_dn_store_format *dn_format =
554 talloc_get_type(ldb_module_get_private(ac->module),
555 struct dsdb_extended_dn_store_format);
556 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
557 /* Strip off extended components */
558 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
559 objectclass->defaultObjectCategory);
560 value = ldb_dn_alloc_linearized(msg, dn);
561 talloc_free(dn);
562 } else {
563 value = talloc_strdup(msg,
564 objectclass->defaultObjectCategory);
566 if (value == NULL) {
567 return ldb_module_oom(ac->module);
570 ret = ldb_msg_add_string(msg, "objectCategory", value);
571 if (ret != LDB_SUCCESS) {
572 return ret;
574 } else {
575 const struct dsdb_class *ocClass =
576 dsdb_class_by_cn_ldb_val(ac->schema,
577 ldb_dn_get_rdn_val(objectcategory));
578 if (ocClass != NULL) {
579 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
580 ocClass->defaultObjectCategory);
581 if (ldb_dn_compare(objectcategory, dn) != 0) {
582 ocClass = NULL;
585 talloc_free(objectcategory);
586 if (ocClass == NULL) {
587 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
588 ldb_dn_get_linearized(msg->dn));
589 return LDB_ERR_OBJECT_CLASS_VIOLATION;
593 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
594 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
595 "TRUE");
598 /* There are very special rules for systemFlags, see MS-ADTS
599 * MS-ADTS 3.1.1.5.2.4 */
601 el = ldb_msg_find_element(msg, "systemFlags");
602 if ((el != NULL) && (el->num_values > 1)) {
603 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
604 ldb_dn_get_linearized(msg->dn));
605 return LDB_ERR_CONSTRAINT_VIOLATION;
608 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
610 ldb_msg_remove_attr(msg, "systemFlags");
612 /* Only the following flags may be set by a client */
613 if (ldb_request_get_control(ac->req,
614 LDB_CONTROL_RELAX_OID) == NULL) {
615 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
616 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
617 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
618 | SYSTEM_FLAG_ATTR_IS_RDN );
621 /* But the last one ("ATTR_IS_RDN") is only allowed on
622 * "attributeSchema" objects. So truncate if it does not fit. */
623 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
624 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
627 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
628 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
629 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
630 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
631 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
632 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
633 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
634 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
635 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
636 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
637 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
638 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
639 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
641 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
643 if (el || systemFlags != 0) {
644 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
645 systemFlags);
646 if (ret != LDB_SUCCESS) {
647 return ret;
651 /* make sure that "isCriticalSystemObject" is not specified! */
652 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
653 if ((el != NULL) &&
654 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
655 ldb_set_errstring(ldb,
656 "objectclass: 'isCriticalSystemObject' must not be specified!");
657 return LDB_ERR_UNWILLING_TO_PERFORM;
661 ret = ldb_build_add_req(&add_req, ldb, ac,
662 msg,
663 ac->req->controls,
664 ac, oc_op_callback,
665 ac->req);
666 LDB_REQ_SET_LOCATION(add_req);
667 if (ret != LDB_SUCCESS) {
668 return ret;
671 /* perform the add */
672 return ldb_next_request(ac->module, add_req);
675 static int oc_modify_callback(struct ldb_request *req,
676 struct ldb_reply *ares);
677 static int objectclass_do_mod(struct oc_context *ac);
679 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
681 struct ldb_context *ldb = ldb_module_get_ctx(module);
682 struct ldb_message_element *objectclass_element;
683 struct ldb_message *msg;
684 struct ldb_request *down_req;
685 struct oc_context *ac;
686 bool oc_changes = false;
687 int ret;
689 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
691 /* do not manipulate our control entries */
692 if (ldb_dn_is_special(req->op.mod.message->dn)) {
693 return ldb_next_request(module, req);
696 /* As with the "real" AD we don't accept empty messages */
697 if (req->op.mod.message->num_elements == 0) {
698 ldb_set_errstring(ldb, "objectclass: modify message must have "
699 "elements/attributes!");
700 return LDB_ERR_UNWILLING_TO_PERFORM;
703 ac = oc_init_context(module, req);
704 if (ac == NULL) {
705 return ldb_operr(ldb);
708 /* Without schema, there isn't much to do here */
709 if (ac->schema == NULL) {
710 talloc_free(ac);
711 return ldb_next_request(module, req);
714 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
715 if (msg == NULL) {
716 return ldb_module_oom(ac->module);
719 /* For now change everything except the objectclasses */
721 objectclass_element = ldb_msg_find_element(msg, "objectClass");
722 if (objectclass_element != NULL) {
723 ldb_msg_remove_attr(msg, "objectClass");
724 oc_changes = true;
727 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
728 * only on application NCs - not on the default ones */
729 if (oc_changes &&
730 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
731 struct ldb_dn *nc_root;
733 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
734 &nc_root);
735 if (ret != LDB_SUCCESS) {
736 return ret;
739 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
740 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
741 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
742 ldb_set_errstring(ldb,
743 "objectclass: object class changes on objects under the standard name contexts not allowed!");
744 return LDB_ERR_UNWILLING_TO_PERFORM;
747 talloc_free(nc_root);
750 ret = ldb_build_mod_req(&down_req, ldb, ac,
751 msg,
752 req->controls, ac,
753 oc_changes ? oc_modify_callback : oc_op_callback,
754 req);
755 LDB_REQ_SET_LOCATION(down_req);
756 if (ret != LDB_SUCCESS) {
757 return ret;
760 return ldb_next_request(module, down_req);
763 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
765 static const char * const attrs[] = { "objectClass", NULL };
766 struct ldb_context *ldb;
767 struct ldb_request *search_req;
768 struct oc_context *ac;
769 int ret;
771 ac = talloc_get_type(req->context, struct oc_context);
772 ldb = ldb_module_get_ctx(ac->module);
774 if (!ares) {
775 return ldb_module_done(ac->req, NULL, NULL,
776 LDB_ERR_OPERATIONS_ERROR);
779 if (ares->type == LDB_REPLY_REFERRAL) {
780 return ldb_module_send_referral(ac->req, ares->referral);
783 if (ares->error != LDB_SUCCESS) {
784 return ldb_module_done(ac->req, ares->controls,
785 ares->response, ares->error);
788 if (ares->type != LDB_REPLY_DONE) {
789 talloc_free(ares);
790 return ldb_module_done(ac->req, NULL, NULL,
791 LDB_ERR_OPERATIONS_ERROR);
794 talloc_free(ares);
796 /* this looks up the real existing object for fetching some important
797 * information (objectclasses) */
798 ret = ldb_build_search_req(&search_req, ldb,
799 ac, ac->req->op.mod.message->dn,
800 LDB_SCOPE_BASE,
801 "(objectClass=*)",
802 attrs, NULL,
803 ac, get_search_callback,
804 ac->req);
805 LDB_REQ_SET_LOCATION(search_req);
806 if (ret != LDB_SUCCESS) {
807 return ldb_module_done(ac->req, NULL, NULL, ret);
810 ac->step_fn = objectclass_do_mod;
812 ret = ldb_next_request(ac->module, search_req);
813 if (ret != LDB_SUCCESS) {
814 return ldb_module_done(ac->req, NULL, NULL, ret);
817 return LDB_SUCCESS;
820 static int objectclass_do_mod(struct oc_context *ac)
822 struct ldb_context *ldb;
823 struct ldb_request *mod_req;
824 struct ldb_message_element *oc_el_entry, *oc_el_change;
825 struct ldb_val *vals;
826 struct ldb_message *msg;
827 TALLOC_CTX *mem_ctx;
828 const struct dsdb_class *objectclass;
829 unsigned int i, j, k;
830 bool found;
831 int ret;
833 ldb = ldb_module_get_ctx(ac->module);
835 /* we should always have a valid entry when we enter here */
836 if (ac->search_res == NULL) {
837 return ldb_operr(ldb);
840 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
841 "objectClass");
842 if (oc_el_entry == NULL) {
843 /* existing entry without a valid object class? */
844 return ldb_operr(ldb);
847 /* use a new message structure */
848 msg = ldb_msg_new(ac);
849 if (msg == NULL) {
850 return ldb_module_oom(ac->module);
853 msg->dn = ac->req->op.mod.message->dn;
855 mem_ctx = talloc_new(ac);
856 if (mem_ctx == NULL) {
857 return ldb_module_oom(ac->module);
860 /* We've to walk over all "objectClass" message elements */
861 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
862 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
863 "objectClass") != 0) {
864 continue;
867 oc_el_change = &ac->req->op.mod.message->elements[k];
869 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
870 case LDB_FLAG_MOD_ADD:
871 /* Merge the two message elements */
872 for (i = 0; i < oc_el_change->num_values; i++) {
873 for (j = 0; j < oc_el_entry->num_values; j++) {
874 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
875 (char *)oc_el_entry->values[j].data) == 0) {
876 ldb_asprintf_errstring(ldb,
877 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
878 (int)oc_el_change->values[i].length,
879 (const char *)oc_el_change->values[i].data);
880 talloc_free(mem_ctx);
881 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
884 /* append the new object class value - code was
885 * copied from "ldb_msg_add_value" */
886 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
887 struct ldb_val,
888 oc_el_entry->num_values + 1);
889 if (vals == NULL) {
890 talloc_free(mem_ctx);
891 return ldb_module_oom(ac->module);
893 oc_el_entry->values = vals;
894 oc_el_entry->values[oc_el_entry->num_values] =
895 oc_el_change->values[i];
896 ++(oc_el_entry->num_values);
899 break;
901 case LDB_FLAG_MOD_REPLACE:
903 * In this case the new "oc_el_entry" is simply
904 * "oc_el_change"
906 oc_el_entry = oc_el_change;
908 break;
910 case LDB_FLAG_MOD_DELETE:
911 /* Merge the two message elements */
912 for (i = 0; i < oc_el_change->num_values; i++) {
913 found = false;
914 for (j = 0; j < oc_el_entry->num_values; j++) {
915 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
916 (char *)oc_el_entry->values[j].data) == 0) {
917 found = true;
918 /* delete the object class value
919 * - code was copied from
920 * "ldb_msg_remove_element" */
921 if (j != oc_el_entry->num_values - 1) {
922 memmove(&oc_el_entry->values[j],
923 &oc_el_entry->values[j+1],
924 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
926 --(oc_el_entry->num_values);
927 break;
930 if (!found) {
931 /* we cannot delete a not existing
932 * object class */
933 ldb_asprintf_errstring(ldb,
934 "objectclass: cannot delete this objectclass: '%.*s'!",
935 (int)oc_el_change->values[i].length,
936 (const char *)oc_el_change->values[i].data);
937 talloc_free(mem_ctx);
938 return LDB_ERR_NO_SUCH_ATTRIBUTE;
942 break;
945 /* Now do the sorting */
946 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, mem_ctx,
947 oc_el_entry, msg, oc_el_entry);
948 if (ret != LDB_SUCCESS) {
949 talloc_free(mem_ctx);
950 return ret;
954 * Get the new top-most structural object class and check for
955 * unrelated structural classes
957 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
958 if (objectclass == NULL) {
959 ldb_set_errstring(ldb,
960 "objectclass: cannot delete all structural objectclasses!");
961 talloc_free(mem_ctx);
962 return LDB_ERR_OBJECT_CLASS_VIOLATION;
965 /* Check for unrelated objectclasses */
966 ret = check_unrelated_objectclasses(ac->module, ac->schema,
967 objectclass,
968 oc_el_entry);
969 if (ret != LDB_SUCCESS) {
970 talloc_free(mem_ctx);
971 return ret;
975 talloc_free(mem_ctx);
977 /* Now add the new object class attribute to the change message */
978 ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
979 if (ret != LDB_SUCCESS) {
980 ldb_module_oom(ac->module);
981 return ret;
984 /* Now we have the real and definitive change left to do */
986 ret = ldb_build_mod_req(&mod_req, ldb, ac,
987 msg,
988 ac->req->controls,
989 ac, oc_op_callback,
990 ac->req);
991 LDB_REQ_SET_LOCATION(mod_req);
992 if (ret != LDB_SUCCESS) {
993 return ret;
996 return ldb_next_request(ac->module, mod_req);
999 static int objectclass_do_rename(struct oc_context *ac);
1001 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1003 static const char * const attrs[] = { "objectClass", NULL };
1004 struct ldb_context *ldb;
1005 struct ldb_request *search_req;
1006 struct oc_context *ac;
1007 struct ldb_dn *parent_dn;
1008 int ret;
1010 ldb = ldb_module_get_ctx(module);
1012 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1014 /* do not manipulate our control entries */
1015 if (ldb_dn_is_special(req->op.rename.olddn)) {
1016 return ldb_next_request(module, req);
1019 ac = oc_init_context(module, req);
1020 if (ac == NULL) {
1021 return ldb_operr(ldb);
1024 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1025 if (parent_dn == NULL) {
1026 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1027 ldb_dn_get_linearized(req->op.rename.olddn));
1028 return LDB_ERR_NO_SUCH_OBJECT;
1031 /* this looks up the parent object for fetching some important
1032 * information (objectclasses, DN normalisation...) */
1033 ret = ldb_build_search_req(&search_req, ldb,
1034 ac, parent_dn, LDB_SCOPE_BASE,
1035 "(objectClass=*)",
1036 attrs, NULL,
1037 ac, get_search_callback,
1038 req);
1039 LDB_REQ_SET_LOCATION(search_req);
1040 if (ret != LDB_SUCCESS) {
1041 return ret;
1044 /* we have to add the show recycled control, as otherwise DRS
1045 deletes will be refused as we will think the target parent
1046 does not exist */
1047 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1048 false, NULL);
1050 if (ret != LDB_SUCCESS) {
1051 return ret;
1054 ac->step_fn = objectclass_do_rename;
1056 return ldb_next_request(ac->module, search_req);
1059 static int objectclass_do_rename2(struct oc_context *ac);
1061 static int objectclass_do_rename(struct oc_context *ac)
1063 static const char * const attrs[] = { "objectClass", NULL };
1064 struct ldb_context *ldb;
1065 struct ldb_request *search_req;
1066 int ret;
1068 ldb = ldb_module_get_ctx(ac->module);
1070 /* Check if we have a valid parent - this check is needed since
1071 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1072 if (ac->search_res == NULL) {
1073 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1074 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1075 return LDB_ERR_OTHER;
1078 /* now assign "search_res2" to the parent entry to have "search_res"
1079 * free for another lookup */
1080 ac->search_res2 = ac->search_res;
1081 ac->search_res = NULL;
1083 /* this looks up the real existing object for fetching some important
1084 * information (objectclasses) */
1085 ret = ldb_build_search_req(&search_req, ldb,
1086 ac, ac->req->op.rename.olddn,
1087 LDB_SCOPE_BASE,
1088 "(objectClass=*)",
1089 attrs, NULL,
1090 ac, get_search_callback,
1091 ac->req);
1092 LDB_REQ_SET_LOCATION(search_req);
1093 if (ret != LDB_SUCCESS) {
1094 return ret;
1097 ac->step_fn = objectclass_do_rename2;
1099 return ldb_next_request(ac->module, search_req);
1102 static int objectclass_do_rename2(struct oc_context *ac)
1104 struct ldb_context *ldb;
1105 struct ldb_request *rename_req;
1106 struct ldb_dn *fixed_dn;
1107 int ret;
1109 ldb = ldb_module_get_ctx(ac->module);
1111 /* Check if we have a valid entry - this check is needed since
1112 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1113 if (ac->search_res == NULL) {
1114 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1115 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1116 return LDB_ERR_NO_SUCH_OBJECT;
1119 if (ac->schema != NULL) {
1120 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1121 const struct dsdb_class *objectclass;
1122 const char *rdn_name;
1123 bool allowed_class = false;
1124 unsigned int i, j;
1125 bool found;
1127 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1128 "objectClass");
1129 if (oc_el_entry == NULL) {
1130 /* existing entry without a valid object class? */
1131 return ldb_operr(ldb);
1133 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1134 if (objectclass == NULL) {
1135 /* existing entry without a valid object class? */
1136 return ldb_operr(ldb);
1139 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1140 if (rdn_name == NULL) {
1141 return ldb_operr(ldb);
1143 found = false;
1144 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1145 const struct dsdb_class *tmp_class =
1146 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1147 &oc_el_entry->values[i]);
1149 if (tmp_class == NULL) continue;
1151 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1152 found = true;
1154 if (!found) {
1155 ldb_asprintf_errstring(ldb,
1156 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1157 rdn_name, objectclass->lDAPDisplayName);
1158 return LDB_ERR_UNWILLING_TO_PERFORM;
1161 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1162 "objectClass");
1163 if (oc_el_parent == NULL) {
1164 /* existing entry without a valid object class? */
1165 return ldb_operr(ldb);
1168 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1169 const struct dsdb_class *sclass;
1171 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1172 &oc_el_parent->values[i]);
1173 if (!sclass) {
1174 /* We don't know this class? what is going on? */
1175 continue;
1177 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1178 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1179 allowed_class = true;
1180 break;
1185 if (!allowed_class) {
1186 ldb_asprintf_errstring(ldb,
1187 "objectclass: structural objectClass %s is not a valid child class for %s",
1188 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1189 return LDB_ERR_NAMING_VIOLATION;
1193 /* Ensure we are not trying to rename it to be a child of itself */
1194 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1195 ac->req->op.rename.newdn) == 0) &&
1196 (ldb_dn_compare(ac->req->op.rename.olddn,
1197 ac->req->op.rename.newdn) != 0)) {
1198 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1199 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1200 return LDB_ERR_UNWILLING_TO_PERFORM;
1203 /* Fix up the DN to be in the standard form, taking
1204 * particular care to match the parent DN */
1205 ret = fix_dn(ldb, ac,
1206 ac->req->op.rename.newdn,
1207 ac->search_res2->message->dn,
1208 &fixed_dn);
1209 if (ret != LDB_SUCCESS) {
1210 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1211 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1212 return ret;
1216 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1217 ac->req->op.rename.olddn, fixed_dn,
1218 ac->req->controls,
1219 ac, oc_op_callback,
1220 ac->req);
1221 LDB_REQ_SET_LOCATION(rename_req);
1222 if (ret != LDB_SUCCESS) {
1223 return ret;
1226 /* perform the rename */
1227 return ldb_next_request(ac->module, rename_req);
1230 static int objectclass_do_delete(struct oc_context *ac);
1232 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1234 static const char * const attrs[] = { "nCName", "objectClass",
1235 "systemFlags",
1236 "isDeleted",
1237 "isCriticalSystemObject", NULL };
1238 struct ldb_context *ldb;
1239 struct ldb_request *search_req;
1240 struct oc_context *ac;
1241 int ret;
1243 ldb = ldb_module_get_ctx(module);
1245 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1247 /* do not manipulate our control entries */
1248 if (ldb_dn_is_special(req->op.del.dn)) {
1249 return ldb_next_request(module, req);
1252 /* Bypass the constraint checks when we do have the "RELAX" control
1253 * set. */
1254 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1255 return ldb_next_request(module, req);
1258 ac = oc_init_context(module, req);
1259 if (ac == NULL) {
1260 return ldb_operr(ldb);
1263 /* this looks up the entry object for fetching some important
1264 * information (object classes, system flags...) */
1265 ret = ldb_build_search_req(&search_req, ldb,
1266 ac, req->op.del.dn, LDB_SCOPE_BASE,
1267 "(objectClass=*)",
1268 attrs, req->controls,
1269 ac, get_search_callback,
1270 req);
1271 LDB_REQ_SET_LOCATION(search_req);
1272 if (ret != LDB_SUCCESS) {
1273 return ret;
1276 ac->step_fn = objectclass_do_delete;
1278 return ldb_next_request(ac->module, search_req);
1281 static int objectclass_do_delete(struct oc_context *ac)
1283 struct ldb_context *ldb;
1284 struct ldb_dn *dn;
1285 int32_t systemFlags;
1286 bool isCriticalSystemObject;
1287 int ret;
1289 ldb = ldb_module_get_ctx(ac->module);
1291 /* Check if we have a valid entry - this check is needed since
1292 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1293 if (ac->search_res == NULL) {
1294 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1295 ldb_dn_get_linearized(ac->req->op.del.dn));
1296 return LDB_ERR_NO_SUCH_OBJECT;
1299 /* DC's ntDSDSA object */
1300 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1301 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1302 ldb_dn_get_linearized(ac->req->op.del.dn));
1303 return LDB_ERR_UNWILLING_TO_PERFORM;
1306 /* DC's rIDSet object */
1307 /* Perform this check only when it does exist - this is needed in order
1308 * to don't let existing provisions break. */
1309 ret = samdb_rid_set_dn(ldb, ac, &dn);
1310 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1311 return ret;
1313 if (ret == LDB_SUCCESS) {
1314 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1315 talloc_free(dn);
1316 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1317 ldb_dn_get_linearized(ac->req->op.del.dn));
1318 return LDB_ERR_UNWILLING_TO_PERFORM;
1320 talloc_free(dn);
1323 /* Only trusted request from system account are allowed to delete
1324 * deleted objects.
1326 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1327 (ldb_req_is_untrusted(ac->req) ||
1328 !dsdb_module_am_system(ac->module))) {
1329 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1330 ldb_dn_get_linearized(ac->req->op.del.dn));
1331 return LDB_ERR_UNWILLING_TO_PERFORM;
1334 /* crossRef objects regarding config, schema and default domain NCs */
1335 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1336 "crossRef") != NULL) {
1337 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1338 "nCName");
1339 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1340 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1341 talloc_free(dn);
1343 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1344 ldb_dn_get_linearized(ac->req->op.del.dn));
1345 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1347 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1348 talloc_free(dn);
1350 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1351 ldb_dn_get_linearized(ac->req->op.del.dn));
1352 return LDB_ERR_UNWILLING_TO_PERFORM;
1354 talloc_free(dn);
1357 /* systemFlags */
1359 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1360 "systemFlags", 0);
1361 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1362 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1363 ldb_dn_get_linearized(ac->req->op.del.dn));
1364 return LDB_ERR_UNWILLING_TO_PERFORM;
1367 /* isCriticalSystemObject - but this only applies on tree delete
1368 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1369 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1370 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1371 "isCriticalSystemObject", false);
1372 if (isCriticalSystemObject) {
1374 * Following the explaination from Microsoft
1375 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1376 * "I finished the investigation on this behavior.
1377 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1378 * every object in the tree will be checked to see if it has isCriticalSystemObject
1379 * set to TRUE, including the root node on which the delete operation is performed
1380 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1381 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1382 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1383 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1386 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1387 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1388 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1389 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1390 ldb_asprintf_errstring(ldb,
1391 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1392 ldb_dn_get_linearized(ac->req->op.del.dn));
1393 return LDB_ERR_UNWILLING_TO_PERFORM;
1398 return ldb_next_request(ac->module, ac->req);
1401 static int objectclass_init(struct ldb_module *module)
1403 struct ldb_context *ldb = ldb_module_get_ctx(module);
1404 int ret;
1406 /* Init everything else */
1407 ret = ldb_next_init(module);
1408 if (ret != LDB_SUCCESS) {
1409 return ret;
1412 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1413 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1415 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1416 if (ret != LDB_SUCCESS) {
1417 ldb_debug(ldb, LDB_DEBUG_ERROR,
1418 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1419 return ldb_operr(ldb);
1422 return ret;
1425 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1426 .name = "objectclass",
1427 .add = objectclass_add,
1428 .modify = objectclass_modify,
1429 .rename = objectclass_rename,
1430 .del = objectclass_delete,
1431 .init_context = objectclass_init
1434 int ldb_objectclass_module_init(const char *version)
1436 LDB_MODULE_CHECK_VERSION(version);
1437 return ldb_register_module(&ldb_objectclass_module_ops);