4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 Copyright (C) Matthias Dieter Wallnöfer 2010-2011
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 * Component: objectClass sorting and constraint checking module
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "librpc/ndr/libndr.h"
42 #include "librpc/gen_ndr/ndr_security.h"
43 #include "libcli/security/security.h"
44 #include "auth/auth.h"
45 #include "param/param.h"
46 #include "../libds/common/flags.h"
47 #include "dsdb/samdb/ldb_modules/util.h"
51 struct ldb_module
*module
;
52 struct ldb_request
*req
;
53 const struct dsdb_schema
*schema
;
55 struct ldb_reply
*search_res
;
56 struct ldb_reply
*search_res2
;
58 int (*step_fn
)(struct oc_context
*);
61 static struct oc_context
*oc_init_context(struct ldb_module
*module
,
62 struct ldb_request
*req
)
64 struct ldb_context
*ldb
;
65 struct oc_context
*ac
;
67 ldb
= ldb_module_get_ctx(module
);
69 ac
= talloc_zero(req
, struct oc_context
);
77 ac
->schema
= dsdb_get_schema(ldb
, ac
);
82 static int objectclass_do_add(struct oc_context
*ac
);
85 * This checks if we have unrelated object classes in our entry's "objectClass"
86 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
87 * or two or more disjunct structural ones.
88 * If one of these conditions are true, blame.
90 static int check_unrelated_objectclasses(struct ldb_module
*module
,
91 const struct dsdb_schema
*schema
,
92 const struct dsdb_class
*struct_objectclass
,
93 struct ldb_message_element
*objectclass_element
)
95 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
103 for (i
= 0; i
< objectclass_element
->num_values
; i
++) {
104 const struct dsdb_class
*tmp_class
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
,
105 &objectclass_element
->values
[i
]);
106 const struct dsdb_class
*tmp_class2
= struct_objectclass
;
108 /* Pointer comparison can be used due to the same schema str. */
109 if (tmp_class
== NULL
||
110 tmp_class
== struct_objectclass
||
111 tmp_class
->objectClassCategory
> 2 ||
112 ldb_attr_cmp(tmp_class
->lDAPDisplayName
, "top") == 0) {
118 ldb_attr_cmp(tmp_class2
->lDAPDisplayName
, "top") != 0) {
119 tmp_class2
= dsdb_class_by_lDAPDisplayName(schema
,
120 tmp_class2
->subClassOf
);
121 if (tmp_class2
== tmp_class
) {
129 ldb_asprintf_errstring(ldb
,
130 "objectclass: the objectclass '%s' seems to be unrelated to %s!",
131 tmp_class
->lDAPDisplayName
,
132 struct_objectclass
->lDAPDisplayName
);
133 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
139 static int get_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
141 struct ldb_context
*ldb
;
142 struct oc_context
*ac
;
145 ac
= talloc_get_type(req
->context
, struct oc_context
);
146 ldb
= ldb_module_get_ctx(ac
->module
);
149 return ldb_module_done(ac
->req
, NULL
, NULL
,
150 LDB_ERR_OPERATIONS_ERROR
);
152 if (ares
->error
!= LDB_SUCCESS
&&
153 ares
->error
!= LDB_ERR_NO_SUCH_OBJECT
) {
154 return ldb_module_done(ac
->req
, ares
->controls
,
155 ares
->response
, ares
->error
);
158 ldb_reset_err_string(ldb
);
160 switch (ares
->type
) {
161 case LDB_REPLY_ENTRY
:
162 if (ac
->search_res
!= NULL
) {
163 ldb_set_errstring(ldb
, "Too many results");
165 return ldb_module_done(ac
->req
, NULL
, NULL
,
166 LDB_ERR_OPERATIONS_ERROR
);
169 ac
->search_res
= talloc_steal(ac
, ares
);
172 case LDB_REPLY_REFERRAL
:
179 ret
= ac
->step_fn(ac
);
180 if (ret
!= LDB_SUCCESS
) {
181 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
189 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
191 This should mean that if the parent is:
192 CN=Users,DC=samba,DC=example,DC=com
193 and a proposed child is
194 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
196 The resulting DN should be:
198 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
201 static int fix_dn(struct ldb_context
*ldb
,
203 struct ldb_dn
*newdn
, struct ldb_dn
*parent_dn
,
204 struct ldb_dn
**fixed_dn
)
206 char *upper_rdn_attr
;
207 const struct ldb_val
*rdn_val
;
209 /* Fix up the DN to be in the standard form, taking particular care to
210 * match the parent DN */
211 *fixed_dn
= ldb_dn_copy(mem_ctx
, parent_dn
);
212 if (*fixed_dn
== NULL
) {
216 /* We need the attribute name in upper case */
217 upper_rdn_attr
= strupper_talloc(*fixed_dn
,
218 ldb_dn_get_rdn_name(newdn
));
219 if (upper_rdn_attr
== NULL
) {
223 /* Create a new child */
224 if (ldb_dn_add_child_fmt(*fixed_dn
, "X=X") == false) {
225 return ldb_operr(ldb
);
228 rdn_val
= ldb_dn_get_rdn_val(newdn
);
229 if (rdn_val
== NULL
) {
230 return ldb_operr(ldb
);
234 /* the rules for rDN length constraints are more complex than
235 this. Until we understand them we need to leave this
236 constraint out. Otherwise we break replication, as windows
237 does sometimes send us rDNs longer than 64 */
238 if (!rdn_val
|| rdn_val
->length
> 64) {
239 DEBUG(2,(__location__
": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn
)));
244 /* And replace it with CN=foo (we need the attribute in upper case) */
245 return ldb_dn_set_component(*fixed_dn
, 0, upper_rdn_attr
, *rdn_val
);
249 static int objectclass_add(struct ldb_module
*module
, struct ldb_request
*req
)
251 struct ldb_context
*ldb
;
252 struct ldb_request
*search_req
;
253 struct oc_context
*ac
;
254 struct ldb_dn
*parent_dn
;
255 const struct ldb_val
*val
;
257 static const char * const parent_attrs
[] = { "objectClass", NULL
};
259 ldb
= ldb_module_get_ctx(module
);
261 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_add\n");
263 /* do not manipulate our control entries */
264 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
265 return ldb_next_request(module
, req
);
268 /* An add operation on the basedn without "NC-add" operation isn't
270 if (ldb_dn_compare(ldb_get_default_basedn(ldb
), req
->op
.add
.message
->dn
) == 0) {
271 unsigned int instanceType
;
273 instanceType
= ldb_msg_find_attr_as_uint(req
->op
.add
.message
,
275 if (!(instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)) {
277 /* When we are trying to readd the root basedn then
278 * this is denied, but with an interesting mechanism:
279 * there is generated a referral with the last
280 * component value as hostname. */
281 val
= ldb_dn_get_component_val(req
->op
.add
.message
->dn
,
282 ldb_dn_get_comp_num(req
->op
.add
.message
->dn
) - 1);
284 return ldb_operr(ldb
);
286 referral_uri
= talloc_asprintf(req
, "ldap://%s/%s", val
->data
,
287 ldb_dn_get_linearized(req
->op
.add
.message
->dn
));
288 if (referral_uri
== NULL
) {
289 return ldb_module_oom(module
);
292 return ldb_module_send_referral(req
, referral_uri
);
296 ac
= oc_init_context(module
, req
);
298 return ldb_operr(ldb
);
301 /* If there isn't a parent, just go on to the add processing */
302 if (ldb_dn_get_comp_num(ac
->req
->op
.add
.message
->dn
) == 1) {
303 return objectclass_do_add(ac
);
306 /* get copy of parent DN */
307 parent_dn
= ldb_dn_get_parent(ac
, ac
->req
->op
.add
.message
->dn
);
308 if (parent_dn
== NULL
) {
309 return ldb_operr(ldb
);
312 ret
= ldb_build_search_req(&search_req
, ldb
,
313 ac
, parent_dn
, LDB_SCOPE_BASE
,
314 "(objectClass=*)", parent_attrs
,
316 ac
, get_search_callback
,
318 LDB_REQ_SET_LOCATION(search_req
);
319 if (ret
!= LDB_SUCCESS
) {
323 ret
= dsdb_request_add_controls(search_req
,
324 DSDB_FLAG_AS_SYSTEM
|
325 DSDB_SEARCH_SHOW_RECYCLED
);
326 if (ret
!= LDB_SUCCESS
) {
330 ac
->step_fn
= objectclass_do_add
;
332 return ldb_next_request(ac
->module
, search_req
);
337 check if this is a special RODC nTDSDSA add
339 static bool check_rodc_ntdsdsa_add(struct oc_context
*ac
,
340 const struct dsdb_class
*objectclass
)
342 struct ldb_control
*rodc_control
;
344 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "nTDSDSA") != 0) {
347 rodc_control
= ldb_request_get_control(ac
->req
, LDB_CONTROL_RODC_DCPROMO_OID
);
352 rodc_control
->critical
= false;
356 static int objectclass_do_add(struct oc_context
*ac
)
358 struct ldb_context
*ldb
= ldb_module_get_ctx(ac
->module
);
359 struct ldb_request
*add_req
;
360 struct ldb_message_element
*objectclass_element
, *el
;
361 struct ldb_message
*msg
;
362 const char *rdn_name
= NULL
;
364 const struct dsdb_class
*objectclass
;
365 struct ldb_dn
*objectcategory
;
366 int32_t systemFlags
= 0;
371 msg
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.add
.message
);
373 return ldb_module_oom(ac
->module
);
376 /* Check if we have a valid parent - this check is needed since
377 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
378 if (ac
->search_res
== NULL
) {
379 unsigned int instanceType
;
381 /* An add operation on partition DNs without "NC-add" operation
383 instanceType
= ldb_msg_find_attr_as_uint(msg
, "instanceType",
385 if (!(instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)) {
386 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, parent does not exist!",
387 ldb_dn_get_linearized(msg
->dn
));
388 return LDB_ERR_NO_SUCH_OBJECT
;
391 /* Don't keep any error messages - we've to add a partition */
392 ldb_set_errstring(ldb
, NULL
);
394 /* Fix up the DN to be in the standard form, taking
395 * particular care to match the parent DN */
396 ret
= fix_dn(ldb
, msg
,
397 ac
->req
->op
.add
.message
->dn
,
398 ac
->search_res
->message
->dn
,
400 if (ret
!= LDB_SUCCESS
) {
401 ldb_asprintf_errstring(ldb
, "objectclass: Could not munge DN %s into normal form",
402 ldb_dn_get_linearized(ac
->req
->op
.add
.message
->dn
));
407 if (ac
->schema
!= NULL
) {
409 * Notice: by the normalization function call in "ldb_request()"
410 * case "LDB_ADD" we have always only *one* "objectClass"
411 * attribute at this stage!
414 objectclass_element
= ldb_msg_find_element(msg
, "objectClass");
415 if (!objectclass_element
) {
416 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, no objectclass specified!",
417 ldb_dn_get_linearized(msg
->dn
));
418 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
420 if (objectclass_element
->num_values
== 0) {
421 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
422 ldb_dn_get_linearized(msg
->dn
));
423 return LDB_ERR_CONSTRAINT_VIOLATION
;
426 /* Now do the sorting */
427 ret
= dsdb_sort_objectClass_attr(ldb
, ac
->schema
,
428 objectclass_element
, msg
,
429 objectclass_element
);
430 if (ret
!= LDB_SUCCESS
) {
435 * Get the new top-most structural object class and check for
436 * unrelated structural classes
438 objectclass
= dsdb_get_last_structural_class(ac
->schema
,
439 objectclass_element
);
440 if (objectclass
== NULL
) {
441 ldb_asprintf_errstring(ldb
,
442 "Failed to find a structural class for %s",
443 ldb_dn_get_linearized(msg
->dn
));
444 return LDB_ERR_UNWILLING_TO_PERFORM
;
447 ret
= check_unrelated_objectclasses(ac
->module
, ac
->schema
,
449 objectclass_element
);
450 if (ret
!= LDB_SUCCESS
) {
454 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
455 if (rdn_name
== NULL
) {
456 return ldb_operr(ldb
);
459 for (i
= 0; (!found
) && (i
< objectclass_element
->num_values
);
461 const struct dsdb_class
*tmp_class
=
462 dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
463 &objectclass_element
->values
[i
]);
465 if (tmp_class
== NULL
) continue;
467 if (ldb_attr_cmp(rdn_name
, tmp_class
->rDNAttID
) == 0)
471 ldb_asprintf_errstring(ldb
,
472 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
473 rdn_name
, objectclass
->lDAPDisplayName
);
474 return LDB_ERR_NAMING_VIOLATION
;
477 if (objectclass
->systemOnly
&&
478 !ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
) &&
479 !check_rodc_ntdsdsa_add(ac
, objectclass
)) {
480 ldb_asprintf_errstring(ldb
,
481 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
482 objectclass
->lDAPDisplayName
,
483 ldb_dn_get_linearized(msg
->dn
));
484 return LDB_ERR_UNWILLING_TO_PERFORM
;
487 if (ac
->search_res
&& ac
->search_res
->message
) {
488 struct ldb_message_element
*oc_el
489 = ldb_msg_find_element(ac
->search_res
->message
, "objectClass");
491 bool allowed_class
= false;
492 for (i
=0; allowed_class
== false && oc_el
&& i
< oc_el
->num_values
; i
++) {
493 const struct dsdb_class
*sclass
;
495 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
498 /* We don't know this class? what is going on? */
501 for (j
=0; sclass
->systemPossibleInferiors
&& sclass
->systemPossibleInferiors
[j
]; j
++) {
502 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, sclass
->systemPossibleInferiors
[j
]) == 0) {
503 allowed_class
= true;
509 if (!allowed_class
) {
510 ldb_asprintf_errstring(ldb
, "structural objectClass %s is not a valid child class for %s",
511 objectclass
->lDAPDisplayName
, ldb_dn_get_linearized(ac
->search_res
->message
->dn
));
512 return LDB_ERR_NAMING_VIOLATION
;
516 objectcategory
= ldb_msg_find_attr_as_dn(ldb
, ac
, msg
,
518 if (objectcategory
== NULL
) {
519 struct dsdb_extended_dn_store_format
*dn_format
=
520 talloc_get_type(ldb_module_get_private(ac
->module
),
521 struct dsdb_extended_dn_store_format
);
522 if (dn_format
&& dn_format
->store_extended_dn_in_ldb
== false) {
523 /* Strip off extended components */
524 struct ldb_dn
*dn
= ldb_dn_new(ac
, ldb
,
525 objectclass
->defaultObjectCategory
);
526 value
= ldb_dn_alloc_linearized(msg
, dn
);
529 value
= talloc_strdup(msg
,
530 objectclass
->defaultObjectCategory
);
533 return ldb_module_oom(ac
->module
);
536 ret
= ldb_msg_add_string(msg
, "objectCategory", value
);
537 if (ret
!= LDB_SUCCESS
) {
541 const struct dsdb_class
*ocClass
=
542 dsdb_class_by_cn_ldb_val(ac
->schema
,
543 ldb_dn_get_rdn_val(objectcategory
));
544 if (ocClass
!= NULL
) {
545 struct ldb_dn
*dn
= ldb_dn_new(ac
, ldb
,
546 ocClass
->defaultObjectCategory
);
547 if (ldb_dn_compare(objectcategory
, dn
) != 0) {
551 talloc_free(objectcategory
);
552 if (ocClass
== NULL
) {
553 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
554 ldb_dn_get_linearized(msg
->dn
));
555 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
559 if (!ldb_msg_find_element(msg
, "showInAdvancedViewOnly") && (objectclass
->defaultHidingValue
== true)) {
560 ldb_msg_add_string(msg
, "showInAdvancedViewOnly",
564 /* There are very special rules for systemFlags, see MS-ADTS
565 * MS-ADTS 3.1.1.5.2.4 */
567 el
= ldb_msg_find_element(msg
, "systemFlags");
568 if ((el
!= NULL
) && (el
->num_values
> 1)) {
569 ldb_asprintf_errstring(ldb
, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
570 ldb_dn_get_linearized(msg
->dn
));
571 return LDB_ERR_CONSTRAINT_VIOLATION
;
574 systemFlags
= ldb_msg_find_attr_as_int(msg
, "systemFlags", 0);
576 ldb_msg_remove_attr(msg
, "systemFlags");
578 /* Only the following flags may be set by a client */
579 if (ldb_request_get_control(ac
->req
,
580 LDB_CONTROL_RELAX_OID
) == NULL
) {
581 systemFlags
&= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
582 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
583 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
584 | SYSTEM_FLAG_ATTR_IS_RDN
);
587 /* But the last one ("ATTR_IS_RDN") is only allowed on
588 * "attributeSchema" objects. So truncate if it does not fit. */
589 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "attributeSchema") != 0) {
590 systemFlags
&= ~SYSTEM_FLAG_ATTR_IS_RDN
;
593 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "server") == 0) {
594 systemFlags
|= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
| SYSTEM_FLAG_CONFIG_ALLOW_RENAME
| SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
);
595 } else if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "site") == 0
596 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "serversContainer") == 0
597 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "nTDSDSA") == 0) {
598 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "site") == 0)
599 systemFlags
|= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME
);
600 systemFlags
|= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE
);
601 } else if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, "siteLink") == 0
602 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "subnet") == 0
603 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "siteLinkBridge") == 0
604 || ldb_attr_cmp(objectclass
->lDAPDisplayName
, "nTDSConnection") == 0) {
605 systemFlags
|= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME
);
607 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
609 if (el
|| systemFlags
!= 0) {
610 ret
= samdb_msg_add_int(ldb
, msg
, msg
, "systemFlags",
612 if (ret
!= LDB_SUCCESS
) {
617 /* make sure that "isCriticalSystemObject" is not specified! */
618 el
= ldb_msg_find_element(msg
, "isCriticalSystemObject");
620 !ldb_request_get_control(ac
->req
, LDB_CONTROL_RELAX_OID
)) {
621 ldb_set_errstring(ldb
,
622 "objectclass: 'isCriticalSystemObject' must not be specified!");
623 return LDB_ERR_UNWILLING_TO_PERFORM
;
627 ret
= ldb_build_add_req(&add_req
, ldb
, ac
,
630 ac
->req
, dsdb_next_callback
,
632 LDB_REQ_SET_LOCATION(add_req
);
633 if (ret
!= LDB_SUCCESS
) {
637 /* perform the add */
638 return ldb_next_request(ac
->module
, add_req
);
641 static int oc_modify_callback(struct ldb_request
*req
,
642 struct ldb_reply
*ares
);
643 static int objectclass_do_mod(struct oc_context
*ac
);
645 static int objectclass_modify(struct ldb_module
*module
, struct ldb_request
*req
)
647 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
648 struct ldb_message_element
*objectclass_element
;
649 struct ldb_message
*msg
;
650 struct ldb_request
*down_req
;
651 struct oc_context
*ac
;
652 bool oc_changes
= false;
655 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_modify\n");
657 /* do not manipulate our control entries */
658 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
659 return ldb_next_request(module
, req
);
662 /* As with the "real" AD we don't accept empty messages */
663 if (req
->op
.mod
.message
->num_elements
== 0) {
664 ldb_set_errstring(ldb
, "objectclass: modify message must have "
665 "elements/attributes!");
666 return LDB_ERR_UNWILLING_TO_PERFORM
;
669 ac
= oc_init_context(module
, req
);
671 return ldb_operr(ldb
);
674 /* Without schema, there isn't much to do here */
675 if (ac
->schema
== NULL
) {
677 return ldb_next_request(module
, req
);
680 msg
= ldb_msg_copy_shallow(ac
, req
->op
.mod
.message
);
682 return ldb_module_oom(ac
->module
);
685 /* For now change everything except the objectclasses */
687 objectclass_element
= ldb_msg_find_element(msg
, "objectClass");
688 if (objectclass_element
!= NULL
) {
689 ldb_msg_remove_attr(msg
, "objectClass");
693 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
694 * only on application NCs - not on the default ones */
696 (dsdb_forest_functional_level(ldb
) < DS_DOMAIN_FUNCTION_2003
)) {
697 struct ldb_dn
*nc_root
;
699 ret
= dsdb_find_nc_root(ldb
, ac
, req
->op
.mod
.message
->dn
,
701 if (ret
!= LDB_SUCCESS
) {
705 if ((ldb_dn_compare(nc_root
, ldb_get_default_basedn(ldb
)) == 0) ||
706 (ldb_dn_compare(nc_root
, ldb_get_config_basedn(ldb
)) == 0) ||
707 (ldb_dn_compare(nc_root
, ldb_get_schema_basedn(ldb
)) == 0)) {
708 ldb_set_errstring(ldb
,
709 "objectclass: object class changes on objects under the standard name contexts not allowed!");
710 return LDB_ERR_UNWILLING_TO_PERFORM
;
713 talloc_free(nc_root
);
717 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
723 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
729 LDB_REQ_SET_LOCATION(down_req
);
730 if (ret
!= LDB_SUCCESS
) {
734 return ldb_next_request(module
, down_req
);
737 static int oc_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
739 static const char * const attrs
[] = { "objectClass", NULL
};
740 struct ldb_context
*ldb
;
741 struct ldb_request
*search_req
;
742 struct oc_context
*ac
;
745 ac
= talloc_get_type(req
->context
, struct oc_context
);
746 ldb
= ldb_module_get_ctx(ac
->module
);
749 return ldb_module_done(ac
->req
, NULL
, NULL
,
750 LDB_ERR_OPERATIONS_ERROR
);
753 if (ares
->type
== LDB_REPLY_REFERRAL
) {
754 return ldb_module_send_referral(ac
->req
, ares
->referral
);
757 if (ares
->error
!= LDB_SUCCESS
) {
758 return ldb_module_done(ac
->req
, ares
->controls
,
759 ares
->response
, ares
->error
);
762 if (ares
->type
!= LDB_REPLY_DONE
) {
764 return ldb_module_done(ac
->req
, NULL
, NULL
,
765 LDB_ERR_OPERATIONS_ERROR
);
770 /* this looks up the real existing object for fetching some important
771 * information (objectclasses) */
772 ret
= ldb_build_search_req(&search_req
, ldb
,
773 ac
, ac
->req
->op
.mod
.message
->dn
,
777 ac
, get_search_callback
,
779 LDB_REQ_SET_LOCATION(search_req
);
780 if (ret
!= LDB_SUCCESS
) {
781 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
784 ret
= dsdb_request_add_controls(search_req
,
785 DSDB_FLAG_AS_SYSTEM
|
786 DSDB_SEARCH_SHOW_RECYCLED
);
787 if (ret
!= LDB_SUCCESS
) {
788 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
791 ac
->step_fn
= objectclass_do_mod
;
793 ret
= ldb_next_request(ac
->module
, search_req
);
794 if (ret
!= LDB_SUCCESS
) {
795 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
801 static int objectclass_do_mod(struct oc_context
*ac
)
803 struct ldb_context
*ldb
;
804 struct ldb_request
*mod_req
;
805 struct ldb_message_element
*oc_el_entry
, *oc_el_change
;
806 struct ldb_val
*vals
;
807 struct ldb_message
*msg
;
808 const struct dsdb_class
*objectclass
;
809 unsigned int i
, j
, k
;
813 ldb
= ldb_module_get_ctx(ac
->module
);
815 /* we should always have a valid entry when we enter here */
816 if (ac
->search_res
== NULL
) {
817 return ldb_operr(ldb
);
820 oc_el_entry
= ldb_msg_find_element(ac
->search_res
->message
,
822 if (oc_el_entry
== NULL
) {
823 /* existing entry without a valid object class? */
824 return ldb_operr(ldb
);
827 /* use a new message structure */
828 msg
= ldb_msg_new(ac
);
830 return ldb_module_oom(ac
->module
);
833 msg
->dn
= ac
->req
->op
.mod
.message
->dn
;
835 /* We've to walk over all "objectClass" message elements */
836 for (k
= 0; k
< ac
->req
->op
.mod
.message
->num_elements
; k
++) {
837 if (ldb_attr_cmp(ac
->req
->op
.mod
.message
->elements
[k
].name
,
838 "objectClass") != 0) {
842 oc_el_change
= &ac
->req
->op
.mod
.message
->elements
[k
];
844 switch (oc_el_change
->flags
& LDB_FLAG_MOD_MASK
) {
845 case LDB_FLAG_MOD_ADD
:
846 /* Merge the two message elements */
847 for (i
= 0; i
< oc_el_change
->num_values
; i
++) {
848 for (j
= 0; j
< oc_el_entry
->num_values
; j
++) {
849 if (ldb_attr_cmp((char *)oc_el_change
->values
[i
].data
,
850 (char *)oc_el_entry
->values
[j
].data
) == 0) {
851 ldb_asprintf_errstring(ldb
,
852 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
853 (int)oc_el_change
->values
[i
].length
,
854 (const char *)oc_el_change
->values
[i
].data
);
855 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
858 /* append the new object class value - code was
859 * copied from "ldb_msg_add_value" */
860 vals
= talloc_realloc(oc_el_entry
, oc_el_entry
->values
,
862 oc_el_entry
->num_values
+ 1);
864 return ldb_module_oom(ac
->module
);
866 oc_el_entry
->values
= vals
;
867 oc_el_entry
->values
[oc_el_entry
->num_values
] =
868 oc_el_change
->values
[i
];
869 ++(oc_el_entry
->num_values
);
874 case LDB_FLAG_MOD_REPLACE
:
876 * In this case the new "oc_el_entry" is simply
879 oc_el_entry
= oc_el_change
;
883 case LDB_FLAG_MOD_DELETE
:
884 /* Merge the two message elements */
885 for (i
= 0; i
< oc_el_change
->num_values
; i
++) {
887 for (j
= 0; j
< oc_el_entry
->num_values
; j
++) {
888 if (ldb_attr_cmp((char *)oc_el_change
->values
[i
].data
,
889 (char *)oc_el_entry
->values
[j
].data
) == 0) {
891 /* delete the object class value
892 * - code was copied from
893 * "ldb_msg_remove_element" */
894 if (j
!= oc_el_entry
->num_values
- 1) {
895 memmove(&oc_el_entry
->values
[j
],
896 &oc_el_entry
->values
[j
+1],
897 ((oc_el_entry
->num_values
-1) - j
)*sizeof(struct ldb_val
));
899 --(oc_el_entry
->num_values
);
904 /* we cannot delete a not existing
906 ldb_asprintf_errstring(ldb
,
907 "objectclass: cannot delete this objectclass: '%.*s'!",
908 (int)oc_el_change
->values
[i
].length
,
909 (const char *)oc_el_change
->values
[i
].data
);
910 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
917 /* Now do the sorting */
918 ret
= dsdb_sort_objectClass_attr(ldb
, ac
->schema
, oc_el_entry
,
920 if (ret
!= LDB_SUCCESS
) {
925 * Get the new top-most structural object class and check for
926 * unrelated structural classes
928 objectclass
= dsdb_get_last_structural_class(ac
->schema
,
930 if (objectclass
== NULL
) {
931 ldb_set_errstring(ldb
,
932 "objectclass: cannot delete all structural objectclasses!");
933 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
936 /* Check for unrelated objectclasses */
937 ret
= check_unrelated_objectclasses(ac
->module
, ac
->schema
,
940 if (ret
!= LDB_SUCCESS
) {
945 /* Now add the new object class attribute to the change message */
946 ret
= ldb_msg_add(msg
, oc_el_entry
, LDB_FLAG_MOD_REPLACE
);
947 if (ret
!= LDB_SUCCESS
) {
948 ldb_module_oom(ac
->module
);
952 /* Now we have the real and definitive change left to do */
954 ret
= ldb_build_mod_req(&mod_req
, ldb
, ac
,
957 ac
->req
, dsdb_next_callback
,
959 LDB_REQ_SET_LOCATION(mod_req
);
960 if (ret
!= LDB_SUCCESS
) {
964 return ldb_next_request(ac
->module
, mod_req
);
967 static int objectclass_do_rename(struct oc_context
*ac
);
969 static int objectclass_rename(struct ldb_module
*module
, struct ldb_request
*req
)
971 static const char * const attrs
[] = { "objectClass", NULL
};
972 struct ldb_context
*ldb
;
973 struct ldb_request
*search_req
;
974 struct oc_context
*ac
;
975 struct ldb_dn
*parent_dn
;
978 ldb
= ldb_module_get_ctx(module
);
980 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_rename\n");
982 /* do not manipulate our control entries */
983 if (ldb_dn_is_special(req
->op
.rename
.olddn
)) {
984 return ldb_next_request(module
, req
);
987 ac
= oc_init_context(module
, req
);
989 return ldb_operr(ldb
);
992 parent_dn
= ldb_dn_get_parent(ac
, req
->op
.rename
.newdn
);
993 if (parent_dn
== NULL
) {
994 ldb_asprintf_errstring(ldb
, "objectclass: Cannot rename %s, the parent DN does not exist!",
995 ldb_dn_get_linearized(req
->op
.rename
.olddn
));
996 return LDB_ERR_NO_SUCH_OBJECT
;
999 /* this looks up the parent object for fetching some important
1000 * information (objectclasses, DN normalisation...) */
1001 ret
= ldb_build_search_req(&search_req
, ldb
,
1002 ac
, parent_dn
, LDB_SCOPE_BASE
,
1005 ac
, get_search_callback
,
1007 LDB_REQ_SET_LOCATION(search_req
);
1008 if (ret
!= LDB_SUCCESS
) {
1012 /* we have to add the show recycled control, as otherwise DRS
1013 deletes will be refused as we will think the target parent
1015 ret
= dsdb_request_add_controls(search_req
,
1016 DSDB_FLAG_AS_SYSTEM
|
1017 DSDB_SEARCH_SHOW_RECYCLED
);
1018 if (ret
!= LDB_SUCCESS
) {
1022 ac
->step_fn
= objectclass_do_rename
;
1024 return ldb_next_request(ac
->module
, search_req
);
1027 static int objectclass_do_rename2(struct oc_context
*ac
);
1029 static int objectclass_do_rename(struct oc_context
*ac
)
1031 static const char * const attrs
[] = { "objectClass", NULL
};
1032 struct ldb_context
*ldb
;
1033 struct ldb_request
*search_req
;
1036 ldb
= ldb_module_get_ctx(ac
->module
);
1038 /* Check if we have a valid parent - this check is needed since
1039 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1040 if (ac
->search_res
== NULL
) {
1041 ldb_asprintf_errstring(ldb
, "objectclass: Cannot rename %s, parent does not exist!",
1042 ldb_dn_get_linearized(ac
->req
->op
.rename
.olddn
));
1043 return LDB_ERR_OTHER
;
1046 /* now assign "search_res2" to the parent entry to have "search_res"
1047 * free for another lookup */
1048 ac
->search_res2
= ac
->search_res
;
1049 ac
->search_res
= NULL
;
1051 /* this looks up the real existing object for fetching some important
1052 * information (objectclasses) */
1053 ret
= ldb_build_search_req(&search_req
, ldb
,
1054 ac
, ac
->req
->op
.rename
.olddn
,
1058 ac
, get_search_callback
,
1060 LDB_REQ_SET_LOCATION(search_req
);
1061 if (ret
!= LDB_SUCCESS
) {
1065 ret
= dsdb_request_add_controls(search_req
,
1066 DSDB_FLAG_AS_SYSTEM
|
1067 DSDB_SEARCH_SHOW_RECYCLED
);
1068 if (ret
!= LDB_SUCCESS
) {
1072 ac
->step_fn
= objectclass_do_rename2
;
1074 return ldb_next_request(ac
->module
, search_req
);
1077 static int objectclass_do_rename2(struct oc_context
*ac
)
1079 struct ldb_context
*ldb
;
1080 struct ldb_request
*rename_req
;
1081 struct ldb_dn
*fixed_dn
;
1084 ldb
= ldb_module_get_ctx(ac
->module
);
1086 /* Check if we have a valid entry - this check is needed since
1087 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1088 if (ac
->search_res
== NULL
) {
1089 ldb_asprintf_errstring(ldb
, "objectclass: Cannot rename %s, entry does not exist!",
1090 ldb_dn_get_linearized(ac
->req
->op
.rename
.olddn
));
1091 return LDB_ERR_NO_SUCH_OBJECT
;
1094 if (ac
->schema
!= NULL
) {
1095 struct ldb_message_element
*oc_el_entry
, *oc_el_parent
;
1096 const struct dsdb_class
*objectclass
;
1097 const char *rdn_name
;
1098 bool allowed_class
= false;
1102 oc_el_entry
= ldb_msg_find_element(ac
->search_res
->message
,
1104 if (oc_el_entry
== NULL
) {
1105 /* existing entry without a valid object class? */
1106 return ldb_operr(ldb
);
1108 objectclass
= dsdb_get_last_structural_class(ac
->schema
,
1110 if (objectclass
== NULL
) {
1111 /* existing entry without a valid object class? */
1112 return ldb_operr(ldb
);
1115 rdn_name
= ldb_dn_get_rdn_name(ac
->req
->op
.rename
.newdn
);
1116 if (rdn_name
== NULL
) {
1117 return ldb_operr(ldb
);
1120 for (i
= 0; (!found
) && (i
< oc_el_entry
->num_values
); i
++) {
1121 const struct dsdb_class
*tmp_class
=
1122 dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
1123 &oc_el_entry
->values
[i
]);
1125 if (tmp_class
== NULL
) continue;
1127 if (ldb_attr_cmp(rdn_name
, tmp_class
->rDNAttID
) == 0)
1131 ldb_asprintf_errstring(ldb
,
1132 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1133 rdn_name
, objectclass
->lDAPDisplayName
);
1134 return LDB_ERR_UNWILLING_TO_PERFORM
;
1137 oc_el_parent
= ldb_msg_find_element(ac
->search_res2
->message
,
1139 if (oc_el_parent
== NULL
) {
1140 /* existing entry without a valid object class? */
1141 return ldb_operr(ldb
);
1144 for (i
=0; allowed_class
== false && i
< oc_el_parent
->num_values
; i
++) {
1145 const struct dsdb_class
*sclass
;
1147 sclass
= dsdb_class_by_lDAPDisplayName_ldb_val(ac
->schema
,
1148 &oc_el_parent
->values
[i
]);
1150 /* We don't know this class? what is going on? */
1153 for (j
=0; sclass
->systemPossibleInferiors
&& sclass
->systemPossibleInferiors
[j
]; j
++) {
1154 if (ldb_attr_cmp(objectclass
->lDAPDisplayName
, sclass
->systemPossibleInferiors
[j
]) == 0) {
1155 allowed_class
= true;
1161 if (!allowed_class
) {
1162 ldb_asprintf_errstring(ldb
,
1163 "objectclass: structural objectClass %s is not a valid child class for %s",
1164 objectclass
->lDAPDisplayName
, ldb_dn_get_linearized(ac
->search_res2
->message
->dn
));
1165 return LDB_ERR_NAMING_VIOLATION
;
1169 /* Ensure we are not trying to rename it to be a child of itself */
1170 if ((ldb_dn_compare_base(ac
->req
->op
.rename
.olddn
,
1171 ac
->req
->op
.rename
.newdn
) == 0) &&
1172 (ldb_dn_compare(ac
->req
->op
.rename
.olddn
,
1173 ac
->req
->op
.rename
.newdn
) != 0)) {
1174 ldb_asprintf_errstring(ldb
, "objectclass: Cannot rename %s to be a child of itself",
1175 ldb_dn_get_linearized(ac
->req
->op
.rename
.olddn
));
1176 return LDB_ERR_UNWILLING_TO_PERFORM
;
1179 /* Fix up the DN to be in the standard form, taking
1180 * particular care to match the parent DN */
1181 ret
= fix_dn(ldb
, ac
,
1182 ac
->req
->op
.rename
.newdn
,
1183 ac
->search_res2
->message
->dn
,
1185 if (ret
!= LDB_SUCCESS
) {
1186 ldb_asprintf_errstring(ldb
, "objectclass: Could not munge DN %s into normal form",
1187 ldb_dn_get_linearized(ac
->req
->op
.rename
.newdn
));
1192 ret
= ldb_build_rename_req(&rename_req
, ldb
, ac
,
1193 ac
->req
->op
.rename
.olddn
, fixed_dn
,
1195 ac
->req
, dsdb_next_callback
,
1197 LDB_REQ_SET_LOCATION(rename_req
);
1198 if (ret
!= LDB_SUCCESS
) {
1202 /* perform the rename */
1203 return ldb_next_request(ac
->module
, rename_req
);
1206 static int objectclass_do_delete(struct oc_context
*ac
);
1208 static int objectclass_delete(struct ldb_module
*module
, struct ldb_request
*req
)
1210 static const char * const attrs
[] = { "nCName", "objectClass",
1213 "isCriticalSystemObject", NULL
};
1214 struct ldb_context
*ldb
;
1215 struct ldb_request
*search_req
;
1216 struct oc_context
*ac
;
1219 ldb
= ldb_module_get_ctx(module
);
1221 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "objectclass_delete\n");
1223 /* do not manipulate our control entries */
1224 if (ldb_dn_is_special(req
->op
.del
.dn
)) {
1225 return ldb_next_request(module
, req
);
1228 /* Bypass the constraint checks when we do have the "RELAX" control
1230 if (ldb_request_get_control(req
, LDB_CONTROL_RELAX_OID
) != NULL
) {
1231 return ldb_next_request(module
, req
);
1234 ac
= oc_init_context(module
, req
);
1236 return ldb_operr(ldb
);
1239 /* this looks up the entry object for fetching some important
1240 * information (object classes, system flags...) */
1241 ret
= ldb_build_search_req(&search_req
, ldb
,
1242 ac
, req
->op
.del
.dn
, LDB_SCOPE_BASE
,
1245 ac
, get_search_callback
,
1247 LDB_REQ_SET_LOCATION(search_req
);
1248 if (ret
!= LDB_SUCCESS
) {
1252 ret
= dsdb_request_add_controls(search_req
,
1253 DSDB_FLAG_AS_SYSTEM
|
1254 DSDB_SEARCH_SHOW_RECYCLED
);
1255 if (ret
!= LDB_SUCCESS
) {
1259 ac
->step_fn
= objectclass_do_delete
;
1261 return ldb_next_request(ac
->module
, search_req
);
1264 static int objectclass_do_delete(struct oc_context
*ac
)
1266 struct ldb_context
*ldb
;
1268 int32_t systemFlags
;
1269 bool isCriticalSystemObject
;
1272 ldb
= ldb_module_get_ctx(ac
->module
);
1274 /* Check if we have a valid entry - this check is needed since
1275 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1276 if (ac
->search_res
== NULL
) {
1277 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, entry does not exist!",
1278 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1279 return LDB_ERR_NO_SUCH_OBJECT
;
1282 /* DC's ntDSDSA object */
1283 if (ldb_dn_compare(ac
->req
->op
.del
.dn
, samdb_ntds_settings_dn(ldb
, ac
)) == 0) {
1284 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1285 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1286 return LDB_ERR_UNWILLING_TO_PERFORM
;
1289 /* DC's rIDSet object */
1290 /* Perform this check only when it does exist - this is needed in order
1291 * to don't let existing provisions break. */
1292 ret
= samdb_rid_set_dn(ldb
, ac
, &dn
);
1293 if ((ret
!= LDB_SUCCESS
) && (ret
!= LDB_ERR_NO_SUCH_OBJECT
)) {
1296 if (ret
== LDB_SUCCESS
) {
1297 if (ldb_dn_compare(ac
->req
->op
.del
.dn
, dn
) == 0) {
1299 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1300 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1301 return LDB_ERR_UNWILLING_TO_PERFORM
;
1306 /* Only trusted request from system account are allowed to delete
1309 if (ldb_msg_check_string_attribute(ac
->search_res
->message
, "isDeleted", "TRUE") &&
1310 (ldb_req_is_untrusted(ac
->req
) ||
1311 !dsdb_module_am_system(ac
->module
))) {
1312 ldb_asprintf_errstring(ldb
, "Delete of '%s' failed",
1313 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1314 return LDB_ERR_UNWILLING_TO_PERFORM
;
1317 /* crossRef objects regarding config, schema and default domain NCs */
1318 if (samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass",
1319 "crossRef") != NULL
) {
1320 dn
= ldb_msg_find_attr_as_dn(ldb
, ac
, ac
->search_res
->message
,
1322 if ((ldb_dn_compare(dn
, ldb_get_default_basedn(ldb
)) == 0) ||
1323 (ldb_dn_compare(dn
, ldb_get_config_basedn(ldb
)) == 0)) {
1326 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1327 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1328 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF
;
1330 if (ldb_dn_compare(dn
, ldb_get_schema_basedn(ldb
)) == 0) {
1333 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1334 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1335 return LDB_ERR_UNWILLING_TO_PERFORM
;
1342 systemFlags
= ldb_msg_find_attr_as_int(ac
->search_res
->message
,
1344 if ((systemFlags
& SYSTEM_FLAG_DISALLOW_DELETE
) != 0) {
1345 ldb_asprintf_errstring(ldb
, "objectclass: Cannot delete %s, it isn't permitted!",
1346 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1347 return LDB_ERR_UNWILLING_TO_PERFORM
;
1350 /* isCriticalSystemObject - but this only applies on tree delete
1351 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1352 if (ldb_request_get_control(ac
->req
, LDB_CONTROL_TREE_DELETE_OID
) != NULL
) {
1353 isCriticalSystemObject
= ldb_msg_find_attr_as_bool(ac
->search_res
->message
,
1354 "isCriticalSystemObject", false);
1355 if (isCriticalSystemObject
) {
1357 * Following the explaination from Microsoft
1358 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1359 * "I finished the investigation on this behavior.
1360 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1361 * every object in the tree will be checked to see if it has isCriticalSystemObject
1362 * set to TRUE, including the root node on which the delete operation is performed
1363 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1364 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1365 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1366 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1369 if (samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "group") == NULL
&&
1370 samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "samDomain") == NULL
&&
1371 samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "samServer") == NULL
&&
1372 samdb_find_attribute(ldb
, ac
->search_res
->message
, "objectClass", "user") == NULL
) {
1373 ldb_asprintf_errstring(ldb
,
1374 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1375 ldb_dn_get_linearized(ac
->req
->op
.del
.dn
));
1376 return LDB_ERR_UNWILLING_TO_PERFORM
;
1381 return ldb_next_request(ac
->module
, ac
->req
);
1384 static int objectclass_init(struct ldb_module
*module
)
1386 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
1389 /* Init everything else */
1390 ret
= ldb_next_init(module
);
1391 if (ret
!= LDB_SUCCESS
) {
1395 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1396 ldb_module_set_private(module
, ldb_get_opaque(ldb
, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME
));
1398 ret
= ldb_mod_register_control(module
, LDB_CONTROL_RODC_DCPROMO_OID
);
1399 if (ret
!= LDB_SUCCESS
) {
1400 ldb_debug(ldb
, LDB_DEBUG_ERROR
,
1401 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1402 return ldb_operr(ldb
);
1408 static const struct ldb_module_ops ldb_objectclass_module_ops
= {
1409 .name
= "objectclass",
1410 .add
= objectclass_add
,
1411 .modify
= objectclass_modify
,
1412 .rename
= objectclass_rename
,
1413 .del
= objectclass_delete
,
1414 .init_context
= objectclass_init
1417 int ldb_objectclass_module_init(const char *version
)
1419 LDB_MODULE_CHECK_VERSION(version
);
1420 return ldb_register_module(&ldb_objectclass_module_ops
);