dsdb-acl: add acl_check_access_on_objectclass() helper
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blobde154ec0180fb9fd96d6e8c2feb7aa1530b570f4
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 the entry!",
131 tmp_class->lDAPDisplayName);
132 return LDB_ERR_OBJECT_CLASS_VIOLATION;
135 return LDB_SUCCESS;
138 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
140 struct ldb_context *ldb;
141 struct oc_context *ac;
142 int ret;
144 ac = talloc_get_type(req->context, struct oc_context);
145 ldb = ldb_module_get_ctx(ac->module);
147 if (!ares) {
148 return ldb_module_done(ac->req, NULL, NULL,
149 LDB_ERR_OPERATIONS_ERROR);
151 if (ares->error != LDB_SUCCESS &&
152 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
153 return ldb_module_done(ac->req, ares->controls,
154 ares->response, ares->error);
157 ldb_reset_err_string(ldb);
159 switch (ares->type) {
160 case LDB_REPLY_ENTRY:
161 if (ac->search_res != NULL) {
162 ldb_set_errstring(ldb, "Too many results");
163 talloc_free(ares);
164 return ldb_module_done(ac->req, NULL, NULL,
165 LDB_ERR_OPERATIONS_ERROR);
168 ac->search_res = talloc_steal(ac, ares);
169 break;
171 case LDB_REPLY_REFERRAL:
172 /* ignore */
173 talloc_free(ares);
174 break;
176 case LDB_REPLY_DONE:
177 talloc_free(ares);
178 ret = ac->step_fn(ac);
179 if (ret != LDB_SUCCESS) {
180 return ldb_module_done(ac->req, NULL, NULL, ret);
182 break;
185 return LDB_SUCCESS;
188 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
190 struct oc_context *ac;
192 ac = talloc_get_type(req->context, struct oc_context);
194 if (!ares) {
195 return ldb_module_done(ac->req, NULL, NULL,
196 LDB_ERR_OPERATIONS_ERROR);
199 if (ares->type == LDB_REPLY_REFERRAL) {
200 return ldb_module_send_referral(ac->req, ares->referral);
203 if (ares->error != LDB_SUCCESS) {
204 return ldb_module_done(ac->req, ares->controls,
205 ares->response, ares->error);
208 if (ares->type != LDB_REPLY_DONE) {
209 talloc_free(ares);
210 return ldb_module_done(ac->req, NULL, NULL,
211 LDB_ERR_OPERATIONS_ERROR);
214 return ldb_module_done(ac->req, ares->controls,
215 ares->response, ares->error);
218 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
220 This should mean that if the parent is:
221 CN=Users,DC=samba,DC=example,DC=com
222 and a proposed child is
223 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
225 The resulting DN should be:
227 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
230 static int fix_dn(struct ldb_context *ldb,
231 TALLOC_CTX *mem_ctx,
232 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
233 struct ldb_dn **fixed_dn)
235 char *upper_rdn_attr;
236 const struct ldb_val *rdn_val;
238 /* Fix up the DN to be in the standard form, taking particular care to
239 * match the parent DN */
240 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
241 if (*fixed_dn == NULL) {
242 return ldb_oom(ldb);
245 /* We need the attribute name in upper case */
246 upper_rdn_attr = strupper_talloc(*fixed_dn,
247 ldb_dn_get_rdn_name(newdn));
248 if (upper_rdn_attr == NULL) {
249 return ldb_oom(ldb);
252 /* Create a new child */
253 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
254 return ldb_operr(ldb);
257 rdn_val = ldb_dn_get_rdn_val(newdn);
258 if (rdn_val == NULL) {
259 return ldb_operr(ldb);
262 #if 0
263 /* the rules for rDN length constraints are more complex than
264 this. Until we understand them we need to leave this
265 constraint out. Otherwise we break replication, as windows
266 does sometimes send us rDNs longer than 64 */
267 if (!rdn_val || rdn_val->length > 64) {
268 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
270 #endif
273 /* And replace it with CN=foo (we need the attribute in upper case) */
274 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
278 static int objectclass_do_add(struct oc_context *ac);
280 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
282 struct ldb_context *ldb;
283 struct ldb_request *search_req;
284 struct oc_context *ac;
285 struct ldb_dn *parent_dn;
286 const struct ldb_val *val;
287 int ret;
288 static const char * const parent_attrs[] = { "objectClass", NULL };
290 ldb = ldb_module_get_ctx(module);
292 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
294 /* do not manipulate our control entries */
295 if (ldb_dn_is_special(req->op.add.message->dn)) {
296 return ldb_next_request(module, req);
299 /* An add operation on the basedn without "NC-add" operation isn't
300 * allowed. */
301 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
302 unsigned int instanceType;
304 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
305 "instanceType", 0);
306 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
307 char *referral_uri;
308 /* When we are trying to readd the root basedn then
309 * this is denied, but with an interesting mechanism:
310 * there is generated a referral with the last
311 * component value as hostname. */
312 val = ldb_dn_get_component_val(req->op.add.message->dn,
313 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
314 if (val == NULL) {
315 return ldb_operr(ldb);
317 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
318 ldb_dn_get_linearized(req->op.add.message->dn));
319 if (referral_uri == NULL) {
320 return ldb_module_oom(module);
323 return ldb_module_send_referral(req, referral_uri);
327 ac = oc_init_context(module, req);
328 if (ac == NULL) {
329 return ldb_operr(ldb);
332 /* If there isn't a parent, just go on to the add processing */
333 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
334 return objectclass_do_add(ac);
337 /* get copy of parent DN */
338 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
339 if (parent_dn == NULL) {
340 return ldb_operr(ldb);
343 ret = ldb_build_search_req(&search_req, ldb,
344 ac, parent_dn, LDB_SCOPE_BASE,
345 "(objectClass=*)", parent_attrs,
346 NULL,
347 ac, get_search_callback,
348 req);
349 LDB_REQ_SET_LOCATION(search_req);
350 if (ret != LDB_SUCCESS) {
351 return ret;
354 ret = dsdb_request_add_controls(search_req,
355 DSDB_FLAG_AS_SYSTEM |
356 DSDB_SEARCH_SHOW_RECYCLED);
357 if (ret != LDB_SUCCESS) {
358 return ret;
361 ac->step_fn = objectclass_do_add;
363 return ldb_next_request(ac->module, search_req);
368 check if this is a special RODC nTDSDSA add
370 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
371 const struct dsdb_class *objectclass)
373 struct ldb_control *rodc_control;
375 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
376 return false;
378 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
379 if (!rodc_control) {
380 return false;
383 rodc_control->critical = false;
384 return true;
387 static int objectclass_do_add(struct oc_context *ac)
389 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
390 struct ldb_request *add_req;
391 struct ldb_message_element *objectclass_element, *el;
392 struct ldb_message *msg;
393 const char *rdn_name = NULL;
394 char *value;
395 const struct dsdb_class *objectclass;
396 struct ldb_dn *objectcategory;
397 int32_t systemFlags = 0;
398 unsigned int i, j;
399 bool found;
400 int ret;
402 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
403 if (msg == NULL) {
404 return ldb_module_oom(ac->module);
407 /* Check if we have a valid parent - this check is needed since
408 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
409 if (ac->search_res == NULL) {
410 unsigned int instanceType;
412 /* An add operation on partition DNs without "NC-add" operation
413 * isn't allowed. */
414 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
416 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
417 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
418 ldb_dn_get_linearized(msg->dn));
419 return LDB_ERR_NO_SUCH_OBJECT;
422 /* Don't keep any error messages - we've to add a partition */
423 ldb_set_errstring(ldb, NULL);
424 } else {
425 /* Fix up the DN to be in the standard form, taking
426 * particular care to match the parent DN */
427 ret = fix_dn(ldb, msg,
428 ac->req->op.add.message->dn,
429 ac->search_res->message->dn,
430 &msg->dn);
431 if (ret != LDB_SUCCESS) {
432 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
433 ldb_dn_get_linearized(ac->req->op.add.message->dn));
434 return ret;
438 if (ac->schema != NULL) {
440 * Notice: by the normalization function call in "ldb_request()"
441 * case "LDB_ADD" we have always only *one* "objectClass"
442 * attribute at this stage!
445 objectclass_element = ldb_msg_find_element(msg, "objectClass");
446 if (!objectclass_element) {
447 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
448 ldb_dn_get_linearized(msg->dn));
449 return LDB_ERR_OBJECT_CLASS_VIOLATION;
451 if (objectclass_element->num_values == 0) {
452 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
453 ldb_dn_get_linearized(msg->dn));
454 return LDB_ERR_CONSTRAINT_VIOLATION;
457 /* Now do the sorting */
458 ret = dsdb_sort_objectClass_attr(ldb, ac->schema,
459 objectclass_element, msg,
460 objectclass_element);
461 if (ret != LDB_SUCCESS) {
462 return ret;
466 * Get the new top-most structural object class and check for
467 * unrelated structural classes
469 objectclass = dsdb_get_last_structural_class(ac->schema,
470 objectclass_element);
471 if (objectclass == NULL) {
472 ldb_asprintf_errstring(ldb,
473 "Failed to find a structural class for %s",
474 ldb_dn_get_linearized(msg->dn));
475 return LDB_ERR_UNWILLING_TO_PERFORM;
478 ret = check_unrelated_objectclasses(ac->module, ac->schema,
479 objectclass,
480 objectclass_element);
481 if (ret != LDB_SUCCESS) {
482 return ret;
485 rdn_name = ldb_dn_get_rdn_name(msg->dn);
486 if (rdn_name == NULL) {
487 return ldb_operr(ldb);
489 found = false;
490 for (i = 0; (!found) && (i < objectclass_element->num_values);
491 i++) {
492 const struct dsdb_class *tmp_class =
493 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
494 &objectclass_element->values[i]);
496 if (tmp_class == NULL) continue;
498 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
499 found = true;
501 if (!found) {
502 ldb_asprintf_errstring(ldb,
503 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
504 rdn_name, objectclass->lDAPDisplayName);
505 return LDB_ERR_NAMING_VIOLATION;
508 if (objectclass->systemOnly &&
509 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
510 !check_rodc_ntdsdsa_add(ac, objectclass)) {
511 ldb_asprintf_errstring(ldb,
512 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
513 objectclass->lDAPDisplayName,
514 ldb_dn_get_linearized(msg->dn));
515 return LDB_ERR_UNWILLING_TO_PERFORM;
518 if (ac->search_res && ac->search_res->message) {
519 struct ldb_message_element *oc_el
520 = ldb_msg_find_element(ac->search_res->message, "objectClass");
522 bool allowed_class = false;
523 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
524 const struct dsdb_class *sclass;
526 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
527 &oc_el->values[i]);
528 if (!sclass) {
529 /* We don't know this class? what is going on? */
530 continue;
532 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
533 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
534 allowed_class = true;
535 break;
540 if (!allowed_class) {
541 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
542 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
543 return LDB_ERR_NAMING_VIOLATION;
547 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
548 "objectCategory");
549 if (objectcategory == NULL) {
550 struct dsdb_extended_dn_store_format *dn_format =
551 talloc_get_type(ldb_module_get_private(ac->module),
552 struct dsdb_extended_dn_store_format);
553 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
554 /* Strip off extended components */
555 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
556 objectclass->defaultObjectCategory);
557 value = ldb_dn_alloc_linearized(msg, dn);
558 talloc_free(dn);
559 } else {
560 value = talloc_strdup(msg,
561 objectclass->defaultObjectCategory);
563 if (value == NULL) {
564 return ldb_module_oom(ac->module);
567 ret = ldb_msg_add_string(msg, "objectCategory", value);
568 if (ret != LDB_SUCCESS) {
569 return ret;
571 } else {
572 const struct dsdb_class *ocClass =
573 dsdb_class_by_cn_ldb_val(ac->schema,
574 ldb_dn_get_rdn_val(objectcategory));
575 if (ocClass != NULL) {
576 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
577 ocClass->defaultObjectCategory);
578 if (ldb_dn_compare(objectcategory, dn) != 0) {
579 ocClass = NULL;
582 talloc_free(objectcategory);
583 if (ocClass == NULL) {
584 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
585 ldb_dn_get_linearized(msg->dn));
586 return LDB_ERR_OBJECT_CLASS_VIOLATION;
590 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
591 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
592 "TRUE");
595 /* There are very special rules for systemFlags, see MS-ADTS
596 * MS-ADTS 3.1.1.5.2.4 */
598 el = ldb_msg_find_element(msg, "systemFlags");
599 if ((el != NULL) && (el->num_values > 1)) {
600 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
601 ldb_dn_get_linearized(msg->dn));
602 return LDB_ERR_CONSTRAINT_VIOLATION;
605 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
607 ldb_msg_remove_attr(msg, "systemFlags");
609 /* Only the following flags may be set by a client */
610 if (ldb_request_get_control(ac->req,
611 LDB_CONTROL_RELAX_OID) == NULL) {
612 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
613 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
614 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
615 | SYSTEM_FLAG_ATTR_IS_RDN );
618 /* But the last one ("ATTR_IS_RDN") is only allowed on
619 * "attributeSchema" objects. So truncate if it does not fit. */
620 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
621 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
624 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
625 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
626 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
627 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
628 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
629 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
630 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
631 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
632 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
633 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
634 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
635 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
636 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
638 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
640 if (el || systemFlags != 0) {
641 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
642 systemFlags);
643 if (ret != LDB_SUCCESS) {
644 return ret;
648 /* make sure that "isCriticalSystemObject" is not specified! */
649 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
650 if ((el != NULL) &&
651 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
652 ldb_set_errstring(ldb,
653 "objectclass: 'isCriticalSystemObject' must not be specified!");
654 return LDB_ERR_UNWILLING_TO_PERFORM;
658 ret = ldb_build_add_req(&add_req, ldb, ac,
659 msg,
660 ac->req->controls,
661 ac, oc_op_callback,
662 ac->req);
663 LDB_REQ_SET_LOCATION(add_req);
664 if (ret != LDB_SUCCESS) {
665 return ret;
668 /* perform the add */
669 return ldb_next_request(ac->module, add_req);
672 static int oc_modify_callback(struct ldb_request *req,
673 struct ldb_reply *ares);
674 static int objectclass_do_mod(struct oc_context *ac);
676 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
678 struct ldb_context *ldb = ldb_module_get_ctx(module);
679 struct ldb_message_element *objectclass_element;
680 struct ldb_message *msg;
681 struct ldb_request *down_req;
682 struct oc_context *ac;
683 bool oc_changes = false;
684 int ret;
686 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
688 /* do not manipulate our control entries */
689 if (ldb_dn_is_special(req->op.mod.message->dn)) {
690 return ldb_next_request(module, req);
693 /* As with the "real" AD we don't accept empty messages */
694 if (req->op.mod.message->num_elements == 0) {
695 ldb_set_errstring(ldb, "objectclass: modify message must have "
696 "elements/attributes!");
697 return LDB_ERR_UNWILLING_TO_PERFORM;
700 ac = oc_init_context(module, req);
701 if (ac == NULL) {
702 return ldb_operr(ldb);
705 /* Without schema, there isn't much to do here */
706 if (ac->schema == NULL) {
707 talloc_free(ac);
708 return ldb_next_request(module, req);
711 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
712 if (msg == NULL) {
713 return ldb_module_oom(ac->module);
716 /* For now change everything except the objectclasses */
718 objectclass_element = ldb_msg_find_element(msg, "objectClass");
719 if (objectclass_element != NULL) {
720 ldb_msg_remove_attr(msg, "objectClass");
721 oc_changes = true;
724 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
725 * only on application NCs - not on the default ones */
726 if (oc_changes &&
727 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
728 struct ldb_dn *nc_root;
730 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
731 &nc_root);
732 if (ret != LDB_SUCCESS) {
733 return ret;
736 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
737 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
738 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
739 ldb_set_errstring(ldb,
740 "objectclass: object class changes on objects under the standard name contexts not allowed!");
741 return LDB_ERR_UNWILLING_TO_PERFORM;
744 talloc_free(nc_root);
747 ret = ldb_build_mod_req(&down_req, ldb, ac,
748 msg,
749 req->controls, ac,
750 oc_changes ? oc_modify_callback : oc_op_callback,
751 req);
752 LDB_REQ_SET_LOCATION(down_req);
753 if (ret != LDB_SUCCESS) {
754 return ret;
757 return ldb_next_request(module, down_req);
760 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
762 static const char * const attrs[] = { "objectClass", NULL };
763 struct ldb_context *ldb;
764 struct ldb_request *search_req;
765 struct oc_context *ac;
766 int ret;
768 ac = talloc_get_type(req->context, struct oc_context);
769 ldb = ldb_module_get_ctx(ac->module);
771 if (!ares) {
772 return ldb_module_done(ac->req, NULL, NULL,
773 LDB_ERR_OPERATIONS_ERROR);
776 if (ares->type == LDB_REPLY_REFERRAL) {
777 return ldb_module_send_referral(ac->req, ares->referral);
780 if (ares->error != LDB_SUCCESS) {
781 return ldb_module_done(ac->req, ares->controls,
782 ares->response, ares->error);
785 if (ares->type != LDB_REPLY_DONE) {
786 talloc_free(ares);
787 return ldb_module_done(ac->req, NULL, NULL,
788 LDB_ERR_OPERATIONS_ERROR);
791 talloc_free(ares);
793 /* this looks up the real existing object for fetching some important
794 * information (objectclasses) */
795 ret = ldb_build_search_req(&search_req, ldb,
796 ac, ac->req->op.mod.message->dn,
797 LDB_SCOPE_BASE,
798 "(objectClass=*)",
799 attrs, NULL,
800 ac, get_search_callback,
801 ac->req);
802 LDB_REQ_SET_LOCATION(search_req);
803 if (ret != LDB_SUCCESS) {
804 return ldb_module_done(ac->req, NULL, NULL, ret);
807 ret = dsdb_request_add_controls(search_req,
808 DSDB_FLAG_AS_SYSTEM |
809 DSDB_SEARCH_SHOW_RECYCLED);
810 if (ret != LDB_SUCCESS) {
811 return ldb_module_done(ac->req, NULL, NULL, ret);
814 ac->step_fn = objectclass_do_mod;
816 ret = ldb_next_request(ac->module, search_req);
817 if (ret != LDB_SUCCESS) {
818 return ldb_module_done(ac->req, NULL, NULL, ret);
821 return LDB_SUCCESS;
824 static int objectclass_do_mod(struct oc_context *ac)
826 struct ldb_context *ldb;
827 struct ldb_request *mod_req;
828 struct ldb_message_element *oc_el_entry, *oc_el_change;
829 struct ldb_val *vals;
830 struct ldb_message *msg;
831 const struct dsdb_class *objectclass;
832 unsigned int i, j, k;
833 bool found;
834 int ret;
836 ldb = ldb_module_get_ctx(ac->module);
838 /* we should always have a valid entry when we enter here */
839 if (ac->search_res == NULL) {
840 return ldb_operr(ldb);
843 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
844 "objectClass");
845 if (oc_el_entry == NULL) {
846 /* existing entry without a valid object class? */
847 return ldb_operr(ldb);
850 /* use a new message structure */
851 msg = ldb_msg_new(ac);
852 if (msg == NULL) {
853 return ldb_module_oom(ac->module);
856 msg->dn = ac->req->op.mod.message->dn;
858 /* We've to walk over all "objectClass" message elements */
859 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
860 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
861 "objectClass") != 0) {
862 continue;
865 oc_el_change = &ac->req->op.mod.message->elements[k];
867 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
868 case LDB_FLAG_MOD_ADD:
869 /* Merge the two message elements */
870 for (i = 0; i < oc_el_change->num_values; i++) {
871 for (j = 0; j < oc_el_entry->num_values; j++) {
872 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
873 (char *)oc_el_entry->values[j].data) == 0) {
874 ldb_asprintf_errstring(ldb,
875 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
876 (int)oc_el_change->values[i].length,
877 (const char *)oc_el_change->values[i].data);
878 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
881 /* append the new object class value - code was
882 * copied from "ldb_msg_add_value" */
883 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
884 struct ldb_val,
885 oc_el_entry->num_values + 1);
886 if (vals == NULL) {
887 return ldb_module_oom(ac->module);
889 oc_el_entry->values = vals;
890 oc_el_entry->values[oc_el_entry->num_values] =
891 oc_el_change->values[i];
892 ++(oc_el_entry->num_values);
895 break;
897 case LDB_FLAG_MOD_REPLACE:
899 * In this case the new "oc_el_entry" is simply
900 * "oc_el_change"
902 oc_el_entry = oc_el_change;
904 break;
906 case LDB_FLAG_MOD_DELETE:
907 /* Merge the two message elements */
908 for (i = 0; i < oc_el_change->num_values; i++) {
909 found = false;
910 for (j = 0; j < oc_el_entry->num_values; j++) {
911 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
912 (char *)oc_el_entry->values[j].data) == 0) {
913 found = true;
914 /* delete the object class value
915 * - code was copied from
916 * "ldb_msg_remove_element" */
917 if (j != oc_el_entry->num_values - 1) {
918 memmove(&oc_el_entry->values[j],
919 &oc_el_entry->values[j+1],
920 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
922 --(oc_el_entry->num_values);
923 break;
926 if (!found) {
927 /* we cannot delete a not existing
928 * object class */
929 ldb_asprintf_errstring(ldb,
930 "objectclass: cannot delete this objectclass: '%.*s'!",
931 (int)oc_el_change->values[i].length,
932 (const char *)oc_el_change->values[i].data);
933 return LDB_ERR_NO_SUCH_ATTRIBUTE;
937 break;
940 /* Now do the sorting */
941 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, oc_el_entry,
942 msg, oc_el_entry);
943 if (ret != LDB_SUCCESS) {
944 return ret;
948 * Get the new top-most structural object class and check for
949 * unrelated structural classes
951 objectclass = dsdb_get_last_structural_class(ac->schema,
952 oc_el_entry);
953 if (objectclass == NULL) {
954 ldb_set_errstring(ldb,
955 "objectclass: cannot delete all structural objectclasses!");
956 return LDB_ERR_OBJECT_CLASS_VIOLATION;
959 /* Check for unrelated objectclasses */
960 ret = check_unrelated_objectclasses(ac->module, ac->schema,
961 objectclass,
962 oc_el_entry);
963 if (ret != LDB_SUCCESS) {
964 return ret;
968 /* Now add the new object class attribute to the change message */
969 ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
970 if (ret != LDB_SUCCESS) {
971 ldb_module_oom(ac->module);
972 return ret;
975 /* Now we have the real and definitive change left to do */
977 ret = ldb_build_mod_req(&mod_req, ldb, ac,
978 msg,
979 ac->req->controls,
980 ac, oc_op_callback,
981 ac->req);
982 LDB_REQ_SET_LOCATION(mod_req);
983 if (ret != LDB_SUCCESS) {
984 return ret;
987 return ldb_next_request(ac->module, mod_req);
990 static int objectclass_do_rename(struct oc_context *ac);
992 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
994 static const char * const attrs[] = { "objectClass", NULL };
995 struct ldb_context *ldb;
996 struct ldb_request *search_req;
997 struct oc_context *ac;
998 struct ldb_dn *parent_dn;
999 int ret;
1001 ldb = ldb_module_get_ctx(module);
1003 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1005 /* do not manipulate our control entries */
1006 if (ldb_dn_is_special(req->op.rename.olddn)) {
1007 return ldb_next_request(module, req);
1010 ac = oc_init_context(module, req);
1011 if (ac == NULL) {
1012 return ldb_operr(ldb);
1015 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1016 if (parent_dn == NULL) {
1017 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1018 ldb_dn_get_linearized(req->op.rename.olddn));
1019 return LDB_ERR_NO_SUCH_OBJECT;
1022 /* this looks up the parent object for fetching some important
1023 * information (objectclasses, DN normalisation...) */
1024 ret = ldb_build_search_req(&search_req, ldb,
1025 ac, parent_dn, LDB_SCOPE_BASE,
1026 "(objectClass=*)",
1027 attrs, NULL,
1028 ac, get_search_callback,
1029 req);
1030 LDB_REQ_SET_LOCATION(search_req);
1031 if (ret != LDB_SUCCESS) {
1032 return ret;
1035 /* we have to add the show recycled control, as otherwise DRS
1036 deletes will be refused as we will think the target parent
1037 does not exist */
1038 ret = dsdb_request_add_controls(search_req,
1039 DSDB_FLAG_AS_SYSTEM |
1040 DSDB_SEARCH_SHOW_RECYCLED);
1041 if (ret != LDB_SUCCESS) {
1042 return ret;
1045 ac->step_fn = objectclass_do_rename;
1047 return ldb_next_request(ac->module, search_req);
1050 static int objectclass_do_rename2(struct oc_context *ac);
1052 static int objectclass_do_rename(struct oc_context *ac)
1054 static const char * const attrs[] = { "objectClass", NULL };
1055 struct ldb_context *ldb;
1056 struct ldb_request *search_req;
1057 int ret;
1059 ldb = ldb_module_get_ctx(ac->module);
1061 /* Check if we have a valid parent - this check is needed since
1062 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1063 if (ac->search_res == NULL) {
1064 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1065 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1066 return LDB_ERR_OTHER;
1069 /* now assign "search_res2" to the parent entry to have "search_res"
1070 * free for another lookup */
1071 ac->search_res2 = ac->search_res;
1072 ac->search_res = NULL;
1074 /* this looks up the real existing object for fetching some important
1075 * information (objectclasses) */
1076 ret = ldb_build_search_req(&search_req, ldb,
1077 ac, ac->req->op.rename.olddn,
1078 LDB_SCOPE_BASE,
1079 "(objectClass=*)",
1080 attrs, NULL,
1081 ac, get_search_callback,
1082 ac->req);
1083 LDB_REQ_SET_LOCATION(search_req);
1084 if (ret != LDB_SUCCESS) {
1085 return ret;
1088 ret = dsdb_request_add_controls(search_req,
1089 DSDB_FLAG_AS_SYSTEM |
1090 DSDB_SEARCH_SHOW_RECYCLED);
1091 if (ret != LDB_SUCCESS) {
1092 return ret;
1095 ac->step_fn = objectclass_do_rename2;
1097 return ldb_next_request(ac->module, search_req);
1100 static int objectclass_do_rename2(struct oc_context *ac)
1102 struct ldb_context *ldb;
1103 struct ldb_request *rename_req;
1104 struct ldb_dn *fixed_dn;
1105 int ret;
1107 ldb = ldb_module_get_ctx(ac->module);
1109 /* Check if we have a valid entry - this check is needed since
1110 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1111 if (ac->search_res == NULL) {
1112 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1113 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1114 return LDB_ERR_NO_SUCH_OBJECT;
1117 if (ac->schema != NULL) {
1118 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1119 const struct dsdb_class *objectclass;
1120 const char *rdn_name;
1121 bool allowed_class = false;
1122 unsigned int i, j;
1123 bool found;
1125 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1126 "objectClass");
1127 if (oc_el_entry == NULL) {
1128 /* existing entry without a valid object class? */
1129 return ldb_operr(ldb);
1131 objectclass = dsdb_get_last_structural_class(ac->schema,
1132 oc_el_entry);
1133 if (objectclass == NULL) {
1134 /* existing entry without a valid object class? */
1135 return ldb_operr(ldb);
1138 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1139 if (rdn_name == NULL) {
1140 return ldb_operr(ldb);
1142 found = false;
1143 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1144 const struct dsdb_class *tmp_class =
1145 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1146 &oc_el_entry->values[i]);
1148 if (tmp_class == NULL) continue;
1150 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1151 found = true;
1153 if (!found) {
1154 ldb_asprintf_errstring(ldb,
1155 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1156 rdn_name, objectclass->lDAPDisplayName);
1157 return LDB_ERR_UNWILLING_TO_PERFORM;
1160 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1161 "objectClass");
1162 if (oc_el_parent == NULL) {
1163 /* existing entry without a valid object class? */
1164 return ldb_operr(ldb);
1167 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1168 const struct dsdb_class *sclass;
1170 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1171 &oc_el_parent->values[i]);
1172 if (!sclass) {
1173 /* We don't know this class? what is going on? */
1174 continue;
1176 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1177 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1178 allowed_class = true;
1179 break;
1184 if (!allowed_class) {
1185 ldb_asprintf_errstring(ldb,
1186 "objectclass: structural objectClass %s is not a valid child class for %s",
1187 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1188 return LDB_ERR_NAMING_VIOLATION;
1192 /* Ensure we are not trying to rename it to be a child of itself */
1193 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1194 ac->req->op.rename.newdn) == 0) &&
1195 (ldb_dn_compare(ac->req->op.rename.olddn,
1196 ac->req->op.rename.newdn) != 0)) {
1197 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1198 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1199 return LDB_ERR_UNWILLING_TO_PERFORM;
1202 /* Fix up the DN to be in the standard form, taking
1203 * particular care to match the parent DN */
1204 ret = fix_dn(ldb, ac,
1205 ac->req->op.rename.newdn,
1206 ac->search_res2->message->dn,
1207 &fixed_dn);
1208 if (ret != LDB_SUCCESS) {
1209 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1210 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1211 return ret;
1215 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1216 ac->req->op.rename.olddn, fixed_dn,
1217 ac->req->controls,
1218 ac, oc_op_callback,
1219 ac->req);
1220 LDB_REQ_SET_LOCATION(rename_req);
1221 if (ret != LDB_SUCCESS) {
1222 return ret;
1225 /* perform the rename */
1226 return ldb_next_request(ac->module, rename_req);
1229 static int objectclass_do_delete(struct oc_context *ac);
1231 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1233 static const char * const attrs[] = { "nCName", "objectClass",
1234 "systemFlags",
1235 "isDeleted",
1236 "isCriticalSystemObject", NULL };
1237 struct ldb_context *ldb;
1238 struct ldb_request *search_req;
1239 struct oc_context *ac;
1240 int ret;
1242 ldb = ldb_module_get_ctx(module);
1244 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1246 /* do not manipulate our control entries */
1247 if (ldb_dn_is_special(req->op.del.dn)) {
1248 return ldb_next_request(module, req);
1251 /* Bypass the constraint checks when we do have the "RELAX" control
1252 * set. */
1253 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1254 return ldb_next_request(module, req);
1257 ac = oc_init_context(module, req);
1258 if (ac == NULL) {
1259 return ldb_operr(ldb);
1262 /* this looks up the entry object for fetching some important
1263 * information (object classes, system flags...) */
1264 ret = ldb_build_search_req(&search_req, ldb,
1265 ac, req->op.del.dn, LDB_SCOPE_BASE,
1266 "(objectClass=*)",
1267 attrs, NULL,
1268 ac, get_search_callback,
1269 req);
1270 LDB_REQ_SET_LOCATION(search_req);
1271 if (ret != LDB_SUCCESS) {
1272 return ret;
1275 ret = dsdb_request_add_controls(search_req,
1276 DSDB_FLAG_AS_SYSTEM |
1277 DSDB_SEARCH_SHOW_RECYCLED);
1278 if (ret != LDB_SUCCESS) {
1279 return ret;
1282 ac->step_fn = objectclass_do_delete;
1284 return ldb_next_request(ac->module, search_req);
1287 static int objectclass_do_delete(struct oc_context *ac)
1289 struct ldb_context *ldb;
1290 struct ldb_dn *dn;
1291 int32_t systemFlags;
1292 bool isCriticalSystemObject;
1293 int ret;
1295 ldb = ldb_module_get_ctx(ac->module);
1297 /* Check if we have a valid entry - this check is needed since
1298 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1299 if (ac->search_res == NULL) {
1300 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1301 ldb_dn_get_linearized(ac->req->op.del.dn));
1302 return LDB_ERR_NO_SUCH_OBJECT;
1305 /* DC's ntDSDSA object */
1306 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb, ac)) == 0) {
1307 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1308 ldb_dn_get_linearized(ac->req->op.del.dn));
1309 return LDB_ERR_UNWILLING_TO_PERFORM;
1312 /* DC's rIDSet object */
1313 /* Perform this check only when it does exist - this is needed in order
1314 * to don't let existing provisions break. */
1315 ret = samdb_rid_set_dn(ldb, ac, &dn);
1316 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1317 return ret;
1319 if (ret == LDB_SUCCESS) {
1320 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1321 talloc_free(dn);
1322 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1323 ldb_dn_get_linearized(ac->req->op.del.dn));
1324 return LDB_ERR_UNWILLING_TO_PERFORM;
1326 talloc_free(dn);
1329 /* Only trusted request from system account are allowed to delete
1330 * deleted objects.
1332 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1333 (ldb_req_is_untrusted(ac->req) ||
1334 !dsdb_module_am_system(ac->module))) {
1335 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1336 ldb_dn_get_linearized(ac->req->op.del.dn));
1337 return LDB_ERR_UNWILLING_TO_PERFORM;
1340 /* crossRef objects regarding config, schema and default domain NCs */
1341 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1342 "crossRef") != NULL) {
1343 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1344 "nCName");
1345 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1346 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1347 talloc_free(dn);
1349 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1350 ldb_dn_get_linearized(ac->req->op.del.dn));
1351 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1353 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1354 talloc_free(dn);
1356 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1357 ldb_dn_get_linearized(ac->req->op.del.dn));
1358 return LDB_ERR_UNWILLING_TO_PERFORM;
1360 talloc_free(dn);
1363 /* systemFlags */
1365 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1366 "systemFlags", 0);
1367 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1368 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1369 ldb_dn_get_linearized(ac->req->op.del.dn));
1370 return LDB_ERR_UNWILLING_TO_PERFORM;
1373 /* isCriticalSystemObject - but this only applies on tree delete
1374 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1375 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1376 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1377 "isCriticalSystemObject", false);
1378 if (isCriticalSystemObject) {
1380 * Following the explaination from Microsoft
1381 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1382 * "I finished the investigation on this behavior.
1383 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1384 * every object in the tree will be checked to see if it has isCriticalSystemObject
1385 * set to TRUE, including the root node on which the delete operation is performed
1386 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1387 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1388 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1389 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1392 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1393 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1394 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1395 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1396 ldb_asprintf_errstring(ldb,
1397 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1398 ldb_dn_get_linearized(ac->req->op.del.dn));
1399 return LDB_ERR_UNWILLING_TO_PERFORM;
1404 return ldb_next_request(ac->module, ac->req);
1407 static int objectclass_init(struct ldb_module *module)
1409 struct ldb_context *ldb = ldb_module_get_ctx(module);
1410 int ret;
1412 /* Init everything else */
1413 ret = ldb_next_init(module);
1414 if (ret != LDB_SUCCESS) {
1415 return ret;
1418 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1419 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1421 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1422 if (ret != LDB_SUCCESS) {
1423 ldb_debug(ldb, LDB_DEBUG_ERROR,
1424 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1425 return ldb_operr(ldb);
1428 return ret;
1431 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1432 .name = "objectclass",
1433 .add = objectclass_add,
1434 .modify = objectclass_modify,
1435 .rename = objectclass_rename,
1436 .del = objectclass_delete,
1437 .init_context = objectclass_init
1440 int ldb_objectclass_module_init(const char *version)
1442 LDB_MODULE_CHECK_VERSION(version);
1443 return ldb_register_module(&ldb_objectclass_module_ops);