4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 Copyright (C) Matthias Dieter Wallnöfer 2010-2011
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: objectClass sorting and constraint checking module
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "librpc/ndr/libndr.h"
42 #include "librpc/gen_ndr/ndr_security.h"
43 #include "libcli/security/security.h"
44 #include "auth/auth.h"
45 #include "param/param.h"
46 #include "../libds/common/flags.h"
47 #include "dsdb/samdb/ldb_modules/util.h"
51 struct ldb_module
*module
;
52 struct ldb_request
*req
;
53 const struct dsdb_schema
*schema
;
55 struct ldb_reply
*search_res
;
56 struct ldb_reply
*search_res2
;
58 int (*step_fn
)(struct oc_context
*);
61 static struct oc_context
*oc_init_context(struct ldb_module
*module
,
62 struct ldb_request
*req
)
64 struct ldb_context
*ldb
;
65 struct oc_context
*ac
;
67 ldb
= ldb_module_get_ctx(module
);
69 ac
= talloc_zero(req
, struct oc_context
);
77 ac
->schema
= dsdb_get_schema(ldb
, ac
);
82 static int objectclass_do_add(struct oc_context
*ac
);
85 * This checks if we have unrelated object classes in our entry's "objectClass"
86 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
87 * or two or more disjunct structural ones.
88 * If one of these conditions are true, blame.
90 static int check_unrelated_objectclasses(struct ldb_module
*module
,
91 const struct dsdb_schema
*schema
,
92 const struct dsdb_class
*struct_objectclass
,
93 struct ldb_message_element
*objectclass_element
)
95 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
103 for (i
= 0; i
< objectclass_element
->num_values
; i
++) {
104 const struct dsdb_class
*tmp_class
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
,
105 &objectclass_element
->values
[i
]);
106 const struct dsdb_class
*tmp_class2
= struct_objectclass
;
108 /* Pointer comparison can be used due to the same schema str. */
109 if (tmp_class
== NULL
||
110 tmp_class
== struct_objectclass
||
111 tmp_class
->objectClassCategory
> 2 ||
112 ldb_attr_cmp(tmp_class
->lDAPDisplayName
, "top") == 0) {
118 ldb_attr_cmp(tmp_class2
->lDAPDisplayName
, "top") != 0) {
119 tmp_class2
= dsdb_class_by_lDAPDisplayName(schema
,
120 tmp_class2
->subClassOf
);
121 if (tmp_class2
== tmp_class
) {
129 ldb_asprintf_errstring(ldb
,
130 "objectclass: the objectclass '%s' seems to be unrelated to the entry!",
131 tmp_class
->lDAPDisplayName
);
132 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
138 static int get_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
140 struct ldb_context
*ldb
;
141 struct oc_context
*ac
;
144 ac
= talloc_get_type(req
->context
, struct oc_context
);
145 ldb
= ldb_module_get_ctx(ac
->module
);
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");
164 return ldb_module_done(ac
->req
, NULL
, NULL
,
165 LDB_ERR_OPERATIONS_ERROR
);
168 ac
->search_res
= talloc_steal(ac
, ares
);
171 case LDB_REPLY_REFERRAL
:
178 ret
= ac
->step_fn(ac
);
179 if (ret
!= LDB_SUCCESS
) {
180 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
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
);
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
) {
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
,
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
) {
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
) {
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
);
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
)));
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
;
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
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
,
306 if (!(instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)) {
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);
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
);
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
,
347 ac
, get_search_callback
,
349 LDB_REQ_SET_LOCATION(search_req
);
350 if (ret
!= LDB_SUCCESS
) {
354 ac
->step_fn
= objectclass_do_add
;
356 return ldb_next_request(ac
->module
, search_req
);
361 check if this is a special RODC nTDSDSA add
363 static bool check_rodc_ntdsdsa_add(struct oc_context
*ac
,
364 const struct dsdb_class
*objectclass
)
366 struct ldb_control
*rodc_control
;
368 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "nTDSDSA") != 0) {
371 rodc_control
= ldb_request_get_control(ac
->req
, LDB_CONTROL_RODC_DCPROMO_OID
);
376 rodc_control
->critical
= false;
380 static int objectclass_do_add(struct oc_context
*ac
)
382 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
383 struct ldb_request
*add_req
;
384 struct ldb_message_element
*objectclass_element
, *el
;
385 struct ldb_message
*msg
;
387 const char *rdn_name
= NULL
;
389 const struct dsdb_class
*objectclass
;
390 struct ldb_dn
*objectcategory
;
391 int32_t systemFlags
= 0;
396 msg
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.add
.message
);
398 return ldb_module_oom(ac
->module
);
401 /* Check if we have a valid parent - this check is needed since
402 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
403 if (ac
->search_res
== NULL
) {
404 unsigned int instanceType
;
406 /* An add operation on partition DNs without "NC-add" operation
408 instanceType
= ldb_msg_find_attr_as_uint(msg
, "instanceType",
410 if (!(instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)) {
411 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, parent does not exist!",
412 ldb_dn_get_linearized(msg
->dn
));
413 return LDB_ERR_NO_SUCH_OBJECT
;
416 /* Don't keep any error messages - we've to add a partition */
417 ldb_set_errstring(ldb
, NULL
);
419 /* Fix up the DN to be in the standard form, taking
420 * particular care to match the parent DN */
421 ret
= fix_dn(ldb
, msg
,
422 ac
->req
->op
.add
.message
->dn
,
423 ac
->search_res
->message
->dn
,
425 if (ret
!= LDB_SUCCESS
) {
426 ldb_asprintf_errstring(ldb
, "objectclass: Could not munge DN %s into normal form",
427 ldb_dn_get_linearized(ac
->req
->op
.add
.message
->dn
));
432 if (ac
->schema
!= NULL
) {
434 * Notice: by the normalization function call in "ldb_request()"
435 * case "LDB_ADD" we have always only *one* "objectClass"
436 * attribute at this stage!
439 objectclass_element
= ldb_msg_find_element(msg
, "objectClass");
440 if (!objectclass_element
) {
441 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, no objectclass specified!",
442 ldb_dn_get_linearized(msg
->dn
));
443 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
445 if (objectclass_element
->num_values
== 0) {
446 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
447 ldb_dn_get_linearized(msg
->dn
));
448 return LDB_ERR_CONSTRAINT_VIOLATION
;
451 mem_ctx
= talloc_new(ac
);
452 if (mem_ctx
== NULL
) {
453 return ldb_module_oom(ac
->module
);
456 /* Now do the sorting */
457 ret
= dsdb_sort_objectClass_attr(ldb
, ac
->schema
, mem_ctx
,
458 objectclass_element
, msg
,
459 objectclass_element
);
460 if (ret
!= LDB_SUCCESS
) {
461 talloc_free(mem_ctx
);
465 talloc_free(mem_ctx
);
468 * Get the new top-most structural object class and check for
469 * unrelated structural classes
471 objectclass
= dsdb_get_last_structural_class(ac
->schema
,
472 objectclass_element
);
473 if (objectclass
== NULL
) {
474 ldb_asprintf_errstring(ldb
,
475 "Failed to find a structural class for %s",
476 ldb_dn_get_linearized(msg
->dn
));
477 return LDB_ERR_UNWILLING_TO_PERFORM
;
480 ret
= check_unrelated_objectclasses(ac
->module
, ac
->schema
,
482 objectclass_element
);
483 if (ret
!= LDB_SUCCESS
) {
487 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
488 if (rdn_name
== NULL
) {
489 return ldb_operr(ldb
);
492 for (i
= 0; (!found
) && (i
< objectclass_element
->num_values
);
494 const struct dsdb_class
*tmp_class
=
495 dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
496 &objectclass_element
->values
[i
]);
498 if (tmp_class
== NULL
) continue;
500 if (ldb_attr_cmp(rdn_name
, tmp_class
->rDNAttID
) == 0)
504 ldb_asprintf_errstring(ldb
,
505 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
506 rdn_name
, objectclass
->lDAPDisplayName
);
507 return LDB_ERR_NAMING_VIOLATION
;
510 if (objectclass
->systemOnly
&&
511 !ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
) &&
512 !check_rodc_ntdsdsa_add(ac
, objectclass
)) {
513 ldb_asprintf_errstring(ldb
,
514 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
515 objectclass
->lDAPDisplayName
,
516 ldb_dn_get_linearized(msg
->dn
));
517 return LDB_ERR_UNWILLING_TO_PERFORM
;
520 if (ac
->search_res
&& ac
->search_res
->message
) {
521 struct ldb_message_element
*oc_el
522 = ldb_msg_find_element(ac
->search_res
->message
, "objectClass");
524 bool allowed_class
= false;
525 for (i
=0; allowed_class
== false && oc_el
&& i
< oc_el
->num_values
; i
++) {
526 const struct dsdb_class
*sclass
;
528 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
531 /* We don't know this class? what is going on? */
534 for (j
=0; sclass
->systemPossibleInferiors
&& sclass
->systemPossibleInferiors
[j
]; j
++) {
535 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, sclass
->systemPossibleInferiors
[j
]) == 0) {
536 allowed_class
= true;
542 if (!allowed_class
) {
543 ldb_asprintf_errstring(ldb
, "structural objectClass %s is not a valid child class for %s",
544 objectclass
->lDAPDisplayName
, ldb_dn_get_linearized(ac
->search_res
->message
->dn
));
545 return LDB_ERR_NAMING_VIOLATION
;
549 objectcategory
= ldb_msg_find_attr_as_dn(ldb
, ac
, msg
,
551 if (objectcategory
== NULL
) {
552 struct dsdb_extended_dn_store_format
*dn_format
=
553 talloc_get_type(ldb_module_get_private(ac
->module
),
554 struct dsdb_extended_dn_store_format
);
555 if (dn_format
&& dn_format
->store_extended_dn_in_ldb
== false) {
556 /* Strip off extended components */
557 struct ldb_dn
*dn
= ldb_dn_new(ac
, ldb
,
558 objectclass
->defaultObjectCategory
);
559 value
= ldb_dn_alloc_linearized(msg
, dn
);
562 value
= talloc_strdup(msg
,
563 objectclass
->defaultObjectCategory
);
566 return ldb_module_oom(ac
->module
);
569 ret
= ldb_msg_add_string(msg
, "objectCategory", value
);
570 if (ret
!= LDB_SUCCESS
) {
574 const struct dsdb_class
*ocClass
=
575 dsdb_class_by_cn_ldb_val(ac
->schema
,
576 ldb_dn_get_rdn_val(objectcategory
));
577 if (ocClass
!= NULL
) {
578 struct ldb_dn
*dn
= ldb_dn_new(ac
, ldb
,
579 ocClass
->defaultObjectCategory
);
580 if (ldb_dn_compare(objectcategory
, dn
) != 0) {
584 talloc_free(objectcategory
);
585 if (ocClass
== NULL
) {
586 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
587 ldb_dn_get_linearized(msg
->dn
));
588 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
592 if (!ldb_msg_find_element(msg
, "showInAdvancedViewOnly") && (objectclass
->defaultHidingValue
== true)) {
593 ldb_msg_add_string(msg
, "showInAdvancedViewOnly",
597 /* There are very special rules for systemFlags, see MS-ADTS
598 * MS-ADTS 3.1.1.5.2.4 */
600 el
= ldb_msg_find_element(msg
, "systemFlags");
601 if ((el
!= NULL
) && (el
->num_values
> 1)) {
602 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
603 ldb_dn_get_linearized(msg
->dn
));
604 return LDB_ERR_CONSTRAINT_VIOLATION
;
607 systemFlags
= ldb_msg_find_attr_as_int(msg
, "systemFlags", 0);
609 ldb_msg_remove_attr(msg
, "systemFlags");
611 /* Only the following flags may be set by a client */
612 if (ldb_request_get_control(ac
->req
,
613 LDB_CONTROL_RELAX_OID
) == NULL
) {
614 systemFlags
&= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
615 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
616 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
617 | SYSTEM_FLAG_ATTR_IS_RDN
);
620 /* But the last one ("ATTR_IS_RDN") is only allowed on
621 * "attributeSchema" objects. So truncate if it does not fit. */
622 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "attributeSchema") != 0) {
623 systemFlags
&= ~SYSTEM_FLAG_ATTR_IS_RDN
;
626 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "server") == 0) {
627 systemFlags
|= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
| SYSTEM_FLAG_CONFIG_ALLOW_RENAME
| SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
);
628 } else if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "site") == 0
629 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "serversContainer") == 0
630 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "nTDSDSA") == 0) {
631 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "site") == 0)
632 systemFlags
|= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME
);
633 systemFlags
|= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
);
634 } else if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "siteLink") == 0
635 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "subnet") == 0
636 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "siteLinkBridge") == 0
637 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "nTDSConnection") == 0) {
638 systemFlags
|= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME
);
640 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
642 if (el
|| systemFlags
!= 0) {
643 ret
= samdb_msg_add_int(ldb
, msg
, msg
, "systemFlags",
645 if (ret
!= LDB_SUCCESS
) {
650 /* make sure that "isCriticalSystemObject" is not specified! */
651 el
= ldb_msg_find_element(msg
, "isCriticalSystemObject");
653 !ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
)) {
654 ldb_set_errstring(ldb
,
655 "objectclass: 'isCriticalSystemObject' must not be specified!");
656 return LDB_ERR_UNWILLING_TO_PERFORM
;
660 ret
= ldb_build_add_req(&add_req
, ldb
, ac
,
665 LDB_REQ_SET_LOCATION(add_req
);
666 if (ret
!= LDB_SUCCESS
) {
670 /* perform the add */
671 return ldb_next_request(ac
->module
, add_req
);
674 static int oc_modify_callback(struct ldb_request
*req
,
675 struct ldb_reply
*ares
);
676 static int objectclass_do_mod(struct oc_context
*ac
);
678 static int objectclass_modify(struct ldb_module
*module
, struct ldb_request
*req
)
680 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
681 struct ldb_message_element
*objectclass_element
;
682 struct ldb_message
*msg
;
683 struct ldb_request
*down_req
;
684 struct oc_context
*ac
;
685 bool oc_changes
= false;
688 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_modify\n");
690 /* do not manipulate our control entries */
691 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
692 return ldb_next_request(module
, req
);
695 /* As with the "real" AD we don't accept empty messages */
696 if (req
->op
.mod
.message
->num_elements
== 0) {
697 ldb_set_errstring(ldb
, "objectclass: modify message must have "
698 "elements/attributes!");
699 return LDB_ERR_UNWILLING_TO_PERFORM
;
702 ac
= oc_init_context(module
, req
);
704 return ldb_operr(ldb
);
707 /* Without schema, there isn't much to do here */
708 if (ac
->schema
== NULL
) {
710 return ldb_next_request(module
, req
);
713 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
715 return ldb_module_oom(ac
->module
);
718 /* For now change everything except the objectclasses */
720 objectclass_element
= ldb_msg_find_element(msg
, "objectClass");
721 if (objectclass_element
!= NULL
) {
722 ldb_msg_remove_attr(msg
, "objectClass");
726 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
727 * only on application NCs - not on the default ones */
729 (dsdb_forest_functional_level(ldb
) < DS_DOMAIN_FUNCTION_2003
)) {
730 struct ldb_dn
*nc_root
;
732 ret
= dsdb_find_nc_root(ldb
, ac
, req
->op
.mod
.message
->dn
,
734 if (ret
!= LDB_SUCCESS
) {
738 if ((ldb_dn_compare(nc_root
, ldb_get_default_basedn(ldb
)) == 0) ||
739 (ldb_dn_compare(nc_root
, ldb_get_config_basedn(ldb
)) == 0) ||
740 (ldb_dn_compare(nc_root
, ldb_get_schema_basedn(ldb
)) == 0)) {
741 ldb_set_errstring(ldb
,
742 "objectclass: object class changes on objects under the standard name contexts not allowed!");
743 return LDB_ERR_UNWILLING_TO_PERFORM
;
746 talloc_free(nc_root
);
749 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
752 oc_changes
? oc_modify_callback
: oc_op_callback
,
754 LDB_REQ_SET_LOCATION(down_req
);
755 if (ret
!= LDB_SUCCESS
) {
759 return ldb_next_request(module
, down_req
);
762 static int oc_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
764 static const char * const attrs
[] = { "objectClass", NULL
};
765 struct ldb_context
*ldb
;
766 struct ldb_request
*search_req
;
767 struct oc_context
*ac
;
770 ac
= talloc_get_type(req
->context
, struct oc_context
);
771 ldb
= ldb_module_get_ctx(ac
->module
);
774 return ldb_module_done(ac
->req
, NULL
, NULL
,
775 LDB_ERR_OPERATIONS_ERROR
);
778 if (ares
->type
== LDB_REPLY_REFERRAL
) {
779 return ldb_module_send_referral(ac
->req
, ares
->referral
);
782 if (ares
->error
!= LDB_SUCCESS
) {
783 return ldb_module_done(ac
->req
, ares
->controls
,
784 ares
->response
, ares
->error
);
787 if (ares
->type
!= LDB_REPLY_DONE
) {
789 return ldb_module_done(ac
->req
, NULL
, NULL
,
790 LDB_ERR_OPERATIONS_ERROR
);
795 /* this looks up the real existing object for fetching some important
796 * information (objectclasses) */
797 ret
= ldb_build_search_req(&search_req
, ldb
,
798 ac
, ac
->req
->op
.mod
.message
->dn
,
802 ac
, get_search_callback
,
804 LDB_REQ_SET_LOCATION(search_req
);
805 if (ret
!= LDB_SUCCESS
) {
806 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
809 ac
->step_fn
= objectclass_do_mod
;
811 ret
= ldb_next_request(ac
->module
, search_req
);
812 if (ret
!= LDB_SUCCESS
) {
813 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
819 static int objectclass_do_mod(struct oc_context
*ac
)
821 struct ldb_context
*ldb
;
822 struct ldb_request
*mod_req
;
823 struct ldb_message_element
*oc_el_entry
, *oc_el_change
;
824 struct ldb_val
*vals
;
825 struct ldb_message
*msg
;
827 const struct dsdb_class
*objectclass
;
828 unsigned int i
, j
, k
;
832 ldb
= ldb_module_get_ctx(ac
->module
);
834 /* we should always have a valid entry when we enter here */
835 if (ac
->search_res
== NULL
) {
836 return ldb_operr(ldb
);
839 oc_el_entry
= ldb_msg_find_element(ac
->search_res
->message
,
841 if (oc_el_entry
== NULL
) {
842 /* existing entry without a valid object class? */
843 return ldb_operr(ldb
);
846 /* use a new message structure */
847 msg
= ldb_msg_new(ac
);
849 return ldb_module_oom(ac
->module
);
852 msg
->dn
= ac
->req
->op
.mod
.message
->dn
;
854 mem_ctx
= talloc_new(ac
);
855 if (mem_ctx
== NULL
) {
856 return ldb_module_oom(ac
->module
);
859 /* We've to walk over all "objectClass" message elements */
860 for (k
= 0; k
< ac
->req
->op
.mod
.message
->num_elements
; k
++) {
861 if (ldb_attr_cmp(ac
->req
->op
.mod
.message
->elements
[k
].name
,
862 "objectClass") != 0) {
866 oc_el_change
= &ac
->req
->op
.mod
.message
->elements
[k
];
868 switch (oc_el_change
->flags
& LDB_FLAG_MOD_MASK
) {
869 case LDB_FLAG_MOD_ADD
:
870 /* Merge the two message elements */
871 for (i
= 0; i
< oc_el_change
->num_values
; i
++) {
872 for (j
= 0; j
< oc_el_entry
->num_values
; j
++) {
873 if (ldb_attr_cmp((char *)oc_el_change
->values
[i
].data
,
874 (char *)oc_el_entry
->values
[j
].data
) == 0) {
875 ldb_asprintf_errstring(ldb
,
876 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
877 (int)oc_el_change
->values
[i
].length
,
878 (const char *)oc_el_change
->values
[i
].data
);
879 talloc_free(mem_ctx
);
880 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
883 /* append the new object class value - code was
884 * copied from "ldb_msg_add_value" */
885 vals
= talloc_realloc(oc_el_entry
, oc_el_entry
->values
,
887 oc_el_entry
->num_values
+ 1);
889 talloc_free(mem_ctx
);
890 return ldb_module_oom(ac
->module
);
892 oc_el_entry
->values
= vals
;
893 oc_el_entry
->values
[oc_el_entry
->num_values
] =
894 oc_el_change
->values
[i
];
895 ++(oc_el_entry
->num_values
);
900 case LDB_FLAG_MOD_REPLACE
:
902 * In this case the new "oc_el_entry" is simply
905 oc_el_entry
= oc_el_change
;
909 case LDB_FLAG_MOD_DELETE
:
910 /* Merge the two message elements */
911 for (i
= 0; i
< oc_el_change
->num_values
; i
++) {
913 for (j
= 0; j
< oc_el_entry
->num_values
; j
++) {
914 if (ldb_attr_cmp((char *)oc_el_change
->values
[i
].data
,
915 (char *)oc_el_entry
->values
[j
].data
) == 0) {
917 /* delete the object class value
918 * - code was copied from
919 * "ldb_msg_remove_element" */
920 if (j
!= oc_el_entry
->num_values
- 1) {
921 memmove(&oc_el_entry
->values
[j
],
922 &oc_el_entry
->values
[j
+1],
923 ((oc_el_entry
->num_values
-1) - j
)*sizeof(struct ldb_val
));
925 --(oc_el_entry
->num_values
);
930 /* we cannot delete a not existing
932 ldb_asprintf_errstring(ldb
,
933 "objectclass: cannot delete this objectclass: '%.*s'!",
934 (int)oc_el_change
->values
[i
].length
,
935 (const char *)oc_el_change
->values
[i
].data
);
936 talloc_free(mem_ctx
);
937 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
944 /* Now do the sorting */
945 ret
= dsdb_sort_objectClass_attr(ldb
, ac
->schema
, mem_ctx
,
946 oc_el_entry
, msg
, oc_el_entry
);
947 if (ret
!= LDB_SUCCESS
) {
948 talloc_free(mem_ctx
);
953 * Get the new top-most structural object class and check for
954 * unrelated structural classes
956 objectclass
= dsdb_get_last_structural_class(ac
->schema
,
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
,
969 if (ret
!= LDB_SUCCESS
) {
970 talloc_free(mem_ctx
);
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
);
984 /* Now we have the real and definitive change left to do */
986 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
,
991 LDB_REQ_SET_LOCATION(mod_req
);
992 if (ret
!= LDB_SUCCESS
) {
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
;
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
);
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
,
1037 ac
, get_search_callback
,
1039 LDB_REQ_SET_LOCATION(search_req
);
1040 if (ret
!= LDB_SUCCESS
) {
1044 /* we have to add the show recycled control, as otherwise DRS
1045 deletes will be refused as we will think the target parent
1047 ret
= ldb_request_add_control(search_req
, LDB_CONTROL_SHOW_RECYCLED_OID
,
1050 if (ret
!= LDB_SUCCESS
) {
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
;
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
,
1090 ac
, get_search_callback
,
1092 LDB_REQ_SET_LOCATION(search_req
);
1093 if (ret
!= LDB_SUCCESS
) {
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
;
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;
1127 oc_el_entry
= ldb_msg_find_element(ac
->search_res
->message
,
1129 if (oc_el_entry
== NULL
) {
1130 /* existing entry without a valid object class? */
1131 return ldb_operr(ldb
);
1133 objectclass
= dsdb_get_last_structural_class(ac
->schema
,
1135 if (objectclass
== NULL
) {
1136 /* existing entry without a valid object class? */
1137 return ldb_operr(ldb
);
1140 rdn_name
= ldb_dn_get_rdn_name(ac
->req
->op
.rename
.newdn
);
1141 if (rdn_name
== NULL
) {
1142 return ldb_operr(ldb
);
1145 for (i
= 0; (!found
) && (i
< oc_el_entry
->num_values
); i
++) {
1146 const struct dsdb_class
*tmp_class
=
1147 dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
1148 &oc_el_entry
->values
[i
]);
1150 if (tmp_class
== NULL
) continue;
1152 if (ldb_attr_cmp(rdn_name
, tmp_class
->rDNAttID
) == 0)
1156 ldb_asprintf_errstring(ldb
,
1157 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1158 rdn_name
, objectclass
->lDAPDisplayName
);
1159 return LDB_ERR_UNWILLING_TO_PERFORM
;
1162 oc_el_parent
= ldb_msg_find_element(ac
->search_res2
->message
,
1164 if (oc_el_parent
== NULL
) {
1165 /* existing entry without a valid object class? */
1166 return ldb_operr(ldb
);
1169 for (i
=0; allowed_class
== false && i
< oc_el_parent
->num_values
; i
++) {
1170 const struct dsdb_class
*sclass
;
1172 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
1173 &oc_el_parent
->values
[i
]);
1175 /* We don't know this class? what is going on? */
1178 for (j
=0; sclass
->systemPossibleInferiors
&& sclass
->systemPossibleInferiors
[j
]; j
++) {
1179 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, sclass
->systemPossibleInferiors
[j
]) == 0) {
1180 allowed_class
= true;
1186 if (!allowed_class
) {
1187 ldb_asprintf_errstring(ldb
,
1188 "objectclass: structural objectClass %s is not a valid child class for %s",
1189 objectclass
->lDAPDisplayName
, ldb_dn_get_linearized(ac
->search_res2
->message
->dn
));
1190 return LDB_ERR_NAMING_VIOLATION
;
1194 /* Ensure we are not trying to rename it to be a child of itself */
1195 if ((ldb_dn_compare_base(ac
->req
->op
.rename
.olddn
,
1196 ac
->req
->op
.rename
.newdn
) == 0) &&
1197 (ldb_dn_compare(ac
->req
->op
.rename
.olddn
,
1198 ac
->req
->op
.rename
.newdn
) != 0)) {
1199 ldb_asprintf_errstring(ldb
, "objectclass: Cannot rename %s to be a child of itself",
1200 ldb_dn_get_linearized(ac
->req
->op
.rename
.olddn
));
1201 return LDB_ERR_UNWILLING_TO_PERFORM
;
1204 /* Fix up the DN to be in the standard form, taking
1205 * particular care to match the parent DN */
1206 ret
= fix_dn(ldb
, ac
,
1207 ac
->req
->op
.rename
.newdn
,
1208 ac
->search_res2
->message
->dn
,
1210 if (ret
!= LDB_SUCCESS
) {
1211 ldb_asprintf_errstring(ldb
, "objectclass: Could not munge DN %s into normal form",
1212 ldb_dn_get_linearized(ac
->req
->op
.rename
.newdn
));
1217 ret
= ldb_build_rename_req(&rename_req
, ldb
, ac
,
1218 ac
->req
->op
.rename
.olddn
, fixed_dn
,
1222 LDB_REQ_SET_LOCATION(rename_req
);
1223 if (ret
!= LDB_SUCCESS
) {
1227 /* perform the rename */
1228 return ldb_next_request(ac
->module
, rename_req
);
1231 static int objectclass_do_delete(struct oc_context
*ac
);
1233 static int objectclass_delete(struct ldb_module
*module
, struct ldb_request
*req
)
1235 static const char * const attrs
[] = { "nCName", "objectClass",
1238 "isCriticalSystemObject", NULL
};
1239 struct ldb_context
*ldb
;
1240 struct ldb_request
*search_req
;
1241 struct oc_context
*ac
;
1244 ldb
= ldb_module_get_ctx(module
);
1246 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_delete\n");
1248 /* do not manipulate our control entries */
1249 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
1250 return ldb_next_request(module
, req
);
1253 /* Bypass the constraint checks when we do have the "RELAX" control
1255 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
) != NULL
) {
1256 return ldb_next_request(module
, req
);
1259 ac
= oc_init_context(module
, req
);
1261 return ldb_operr(ldb
);
1264 /* this looks up the entry object for fetching some important
1265 * information (object classes, system flags...) */
1266 ret
= ldb_build_search_req(&search_req
, ldb
,
1267 ac
, req
->op
.del
.dn
, LDB_SCOPE_BASE
,
1269 attrs
, req
->controls
,
1270 ac
, get_search_callback
,
1272 LDB_REQ_SET_LOCATION(search_req
);
1273 if (ret
!= LDB_SUCCESS
) {
1277 ac
->step_fn
= objectclass_do_delete
;
1279 return ldb_next_request(ac
->module
, search_req
);
1282 static int objectclass_do_delete(struct oc_context
*ac
)
1284 struct ldb_context
*ldb
;
1286 int32_t systemFlags
;
1287 bool isCriticalSystemObject
;
1290 ldb
= ldb_module_get_ctx(ac
->module
);
1292 /* Check if we have a valid entry - this check is needed since
1293 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1294 if (ac
->search_res
== NULL
) {
1295 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, entry does not exist!",
1296 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1297 return LDB_ERR_NO_SUCH_OBJECT
;
1300 /* DC's ntDSDSA object */
1301 if (ldb_dn_compare(ac
->req
->op
.del
.dn
, samdb_ntds_settings_dn(ldb
)) == 0) {
1302 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1303 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1304 return LDB_ERR_UNWILLING_TO_PERFORM
;
1307 /* DC's rIDSet object */
1308 /* Perform this check only when it does exist - this is needed in order
1309 * to don't let existing provisions break. */
1310 ret
= samdb_rid_set_dn(ldb
, ac
, &dn
);
1311 if ((ret
!= LDB_SUCCESS
) && (ret
!= LDB_ERR_NO_SUCH_OBJECT
)) {
1314 if (ret
== LDB_SUCCESS
) {
1315 if (ldb_dn_compare(ac
->req
->op
.del
.dn
, dn
) == 0) {
1317 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1318 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1319 return LDB_ERR_UNWILLING_TO_PERFORM
;
1324 /* Only trusted request from system account are allowed to delete
1327 if (ldb_msg_check_string_attribute(ac
->search_res
->message
, "isDeleted", "TRUE") &&
1328 (ldb_req_is_untrusted(ac
->req
) ||
1329 !dsdb_module_am_system(ac
->module
))) {
1330 ldb_asprintf_errstring(ldb
, "Delete of '%s' failed",
1331 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1332 return LDB_ERR_UNWILLING_TO_PERFORM
;
1335 /* crossRef objects regarding config, schema and default domain NCs */
1336 if (samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass",
1337 "crossRef") != NULL
) {
1338 dn
= ldb_msg_find_attr_as_dn(ldb
, ac
, ac
->search_res
->message
,
1340 if ((ldb_dn_compare(dn
, ldb_get_default_basedn(ldb
)) == 0) ||
1341 (ldb_dn_compare(dn
, ldb_get_config_basedn(ldb
)) == 0)) {
1344 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1345 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1346 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF
;
1348 if (ldb_dn_compare(dn
, ldb_get_schema_basedn(ldb
)) == 0) {
1351 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1352 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1353 return LDB_ERR_UNWILLING_TO_PERFORM
;
1360 systemFlags
= ldb_msg_find_attr_as_int(ac
->search_res
->message
,
1362 if ((systemFlags
& SYSTEM_FLAG_DISALLOW_DELETE
) != 0) {
1363 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it isn't permitted!",
1364 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1365 return LDB_ERR_UNWILLING_TO_PERFORM
;
1368 /* isCriticalSystemObject - but this only applies on tree delete
1369 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1370 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_TREE_DELETE_OID
) != NULL
) {
1371 isCriticalSystemObject
= ldb_msg_find_attr_as_bool(ac
->search_res
->message
,
1372 "isCriticalSystemObject", false);
1373 if (isCriticalSystemObject
) {
1375 * Following the explaination from Microsoft
1376 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1377 * "I finished the investigation on this behavior.
1378 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1379 * every object in the tree will be checked to see if it has isCriticalSystemObject
1380 * set to TRUE, including the root node on which the delete operation is performed
1381 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1382 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1383 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1384 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1387 if (samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "group") == NULL
&&
1388 samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "samDomain") == NULL
&&
1389 samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "samServer") == NULL
&&
1390 samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "user") == NULL
) {
1391 ldb_asprintf_errstring(ldb
,
1392 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1393 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1394 return LDB_ERR_UNWILLING_TO_PERFORM
;
1399 return ldb_next_request(ac
->module
, ac
->req
);
1402 static int objectclass_init(struct ldb_module
*module
)
1404 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
1407 /* Init everything else */
1408 ret
= ldb_next_init(module
);
1409 if (ret
!= LDB_SUCCESS
) {
1413 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1414 ldb_module_set_private(module
, ldb_get_opaque(ldb
, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME
));
1416 ret
= ldb_mod_register_control(module
, LDB_CONTROL_RODC_DCPROMO_OID
);
1417 if (ret
!= LDB_SUCCESS
) {
1418 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
1419 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1420 return ldb_operr(ldb
);
1426 static const struct ldb_module_ops ldb_objectclass_module_ops
= {
1427 .name
= "objectclass",
1428 .add
= objectclass_add
,
1429 .modify
= objectclass_modify
,
1430 .rename
= objectclass_rename
,
1431 .del
= objectclass_delete
,
1432 .init_context
= objectclass_init
1435 int ldb_objectclass_module_init(const char *version
)
1437 LDB_MODULE_CHECK_VERSION(version
);
1438 return ldb_register_module(&ldb_objectclass_module_ops
);