librpc: Shorten dcerpc_binding_handle_call a bit
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blobf6f7338d3cf597f2f11058765df1ac3017a53171
1 /*
2 ldb database library
4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 Copyright (C) Matthias Dieter Wallnöfer 2010-2011
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Name: ldb
25 * Component: objectClass sorting and constraint checking module
27 * Description:
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
30 * valid parent),
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "librpc/ndr/libndr.h"
42 #include "librpc/gen_ndr/ndr_security.h"
43 #include "libcli/security/security.h"
44 #include "auth/auth.h"
45 #include "param/param.h"
46 #include "../libds/common/flags.h"
47 #include "dsdb/samdb/ldb_modules/util.h"
49 struct oc_context {
51 struct ldb_module *module;
52 struct ldb_request *req;
53 const struct dsdb_schema *schema;
55 struct ldb_reply *search_res;
56 struct ldb_reply *search_res2;
58 int (*step_fn)(struct oc_context *);
61 static struct oc_context *oc_init_context(struct ldb_module *module,
62 struct ldb_request *req)
64 struct ldb_context *ldb;
65 struct oc_context *ac;
67 ldb = ldb_module_get_ctx(module);
69 ac = talloc_zero(req, struct oc_context);
70 if (ac == NULL) {
71 ldb_oom(ldb);
72 return NULL;
75 ac->module = module;
76 ac->req = req;
77 ac->schema = dsdb_get_schema(ldb, ac);
79 return ac;
82 static int objectclass_do_add(struct oc_context *ac);
85 * This checks if we have unrelated object classes in our entry's "objectClass"
86 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
87 * or two or more disjunct structural ones.
88 * If one of these conditions are true, blame.
90 static int check_unrelated_objectclasses(struct ldb_module *module,
91 const struct dsdb_schema *schema,
92 const struct dsdb_class *struct_objectclass,
93 struct ldb_message_element *objectclass_element)
95 struct ldb_context *ldb = ldb_module_get_ctx(module);
96 unsigned int i;
97 bool found;
99 if (schema == NULL) {
100 return LDB_SUCCESS;
103 for (i = 0; i < objectclass_element->num_values; i++) {
104 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
105 &objectclass_element->values[i]);
106 const struct dsdb_class *tmp_class2 = struct_objectclass;
108 /* Pointer comparison can be used due to the same schema str. */
109 if (tmp_class == NULL ||
110 tmp_class == struct_objectclass ||
111 tmp_class->objectClassCategory > 2 ||
112 ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
113 continue;
116 found = false;
117 while (!found &&
118 ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
119 tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
120 tmp_class2->subClassOf);
121 if (tmp_class2 == tmp_class) {
122 found = true;
125 if (found) {
126 continue;
129 ldb_asprintf_errstring(ldb,
130 "objectclass: the objectclass '%s' seems to be unrelated to %s!",
131 tmp_class->lDAPDisplayName,
132 struct_objectclass->lDAPDisplayName);
133 return LDB_ERR_OBJECT_CLASS_VIOLATION;
136 return LDB_SUCCESS;
139 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
141 struct ldb_context *ldb;
142 struct oc_context *ac;
143 int ret;
145 ac = talloc_get_type(req->context, struct oc_context);
146 ldb = ldb_module_get_ctx(ac->module);
148 if (!ares) {
149 return ldb_module_done(ac->req, NULL, NULL,
150 LDB_ERR_OPERATIONS_ERROR);
152 if (ares->error != LDB_SUCCESS &&
153 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
154 return ldb_module_done(ac->req, ares->controls,
155 ares->response, ares->error);
158 ldb_reset_err_string(ldb);
160 switch (ares->type) {
161 case LDB_REPLY_ENTRY:
162 if (ac->search_res != NULL) {
163 ldb_set_errstring(ldb, "Too many results");
164 talloc_free(ares);
165 return ldb_module_done(ac->req, NULL, NULL,
166 LDB_ERR_OPERATIONS_ERROR);
169 ac->search_res = talloc_steal(ac, ares);
170 break;
172 case LDB_REPLY_REFERRAL:
173 /* ignore */
174 talloc_free(ares);
175 break;
177 case LDB_REPLY_DONE:
178 talloc_free(ares);
179 ret = ac->step_fn(ac);
180 if (ret != LDB_SUCCESS) {
181 return ldb_module_done(ac->req, NULL, NULL, ret);
183 break;
186 return LDB_SUCCESS;
189 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
191 struct oc_context *ac;
193 ac = talloc_get_type(req->context, struct oc_context);
195 if (!ares) {
196 return ldb_module_done(ac->req, NULL, NULL,
197 LDB_ERR_OPERATIONS_ERROR);
200 if (ares->type == LDB_REPLY_REFERRAL) {
201 return ldb_module_send_referral(ac->req, ares->referral);
204 if (ares->error != LDB_SUCCESS) {
205 return ldb_module_done(ac->req, ares->controls,
206 ares->response, ares->error);
209 if (ares->type != LDB_REPLY_DONE) {
210 talloc_free(ares);
211 return ldb_module_done(ac->req, NULL, NULL,
212 LDB_ERR_OPERATIONS_ERROR);
215 return ldb_module_done(ac->req, ares->controls,
216 ares->response, ares->error);
219 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
221 This should mean that if the parent is:
222 CN=Users,DC=samba,DC=example,DC=com
223 and a proposed child is
224 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
226 The resulting DN should be:
228 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
231 static int fix_dn(struct ldb_context *ldb,
232 TALLOC_CTX *mem_ctx,
233 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
234 struct ldb_dn **fixed_dn)
236 char *upper_rdn_attr;
237 const struct ldb_val *rdn_val;
239 /* Fix up the DN to be in the standard form, taking particular care to
240 * match the parent DN */
241 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
242 if (*fixed_dn == NULL) {
243 return ldb_oom(ldb);
246 /* We need the attribute name in upper case */
247 upper_rdn_attr = strupper_talloc(*fixed_dn,
248 ldb_dn_get_rdn_name(newdn));
249 if (upper_rdn_attr == NULL) {
250 return ldb_oom(ldb);
253 /* Create a new child */
254 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
255 return ldb_operr(ldb);
258 rdn_val = ldb_dn_get_rdn_val(newdn);
259 if (rdn_val == NULL) {
260 return ldb_operr(ldb);
263 #if 0
264 /* the rules for rDN length constraints are more complex than
265 this. Until we understand them we need to leave this
266 constraint out. Otherwise we break replication, as windows
267 does sometimes send us rDNs longer than 64 */
268 if (!rdn_val || rdn_val->length > 64) {
269 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
271 #endif
274 /* And replace it with CN=foo (we need the attribute in upper case) */
275 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
279 static int objectclass_do_add(struct oc_context *ac);
281 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
283 struct ldb_context *ldb;
284 struct ldb_request *search_req;
285 struct oc_context *ac;
286 struct ldb_dn *parent_dn;
287 const struct ldb_val *val;
288 int ret;
289 static const char * const parent_attrs[] = { "objectClass", NULL };
291 ldb = ldb_module_get_ctx(module);
293 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
295 /* do not manipulate our control entries */
296 if (ldb_dn_is_special(req->op.add.message->dn)) {
297 return ldb_next_request(module, req);
300 /* An add operation on the basedn without "NC-add" operation isn't
301 * allowed. */
302 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
303 unsigned int instanceType;
305 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
306 "instanceType", 0);
307 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
308 char *referral_uri;
309 /* When we are trying to readd the root basedn then
310 * this is denied, but with an interesting mechanism:
311 * there is generated a referral with the last
312 * component value as hostname. */
313 val = ldb_dn_get_component_val(req->op.add.message->dn,
314 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
315 if (val == NULL) {
316 return ldb_operr(ldb);
318 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
319 ldb_dn_get_linearized(req->op.add.message->dn));
320 if (referral_uri == NULL) {
321 return ldb_module_oom(module);
324 return ldb_module_send_referral(req, referral_uri);
328 ac = oc_init_context(module, req);
329 if (ac == NULL) {
330 return ldb_operr(ldb);
333 /* If there isn't a parent, just go on to the add processing */
334 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
335 return objectclass_do_add(ac);
338 /* get copy of parent DN */
339 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
340 if (parent_dn == NULL) {
341 return ldb_operr(ldb);
344 ret = ldb_build_search_req(&search_req, ldb,
345 ac, parent_dn, LDB_SCOPE_BASE,
346 "(objectClass=*)", parent_attrs,
347 NULL,
348 ac, get_search_callback,
349 req);
350 LDB_REQ_SET_LOCATION(search_req);
351 if (ret != LDB_SUCCESS) {
352 return ret;
355 ret = dsdb_request_add_controls(search_req,
356 DSDB_FLAG_AS_SYSTEM |
357 DSDB_SEARCH_SHOW_RECYCLED);
358 if (ret != LDB_SUCCESS) {
359 return ret;
362 ac->step_fn = objectclass_do_add;
364 return ldb_next_request(ac->module, search_req);
369 check if this is a special RODC nTDSDSA add
371 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
372 const struct dsdb_class *objectclass)
374 struct ldb_control *rodc_control;
376 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
377 return false;
379 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
380 if (!rodc_control) {
381 return false;
384 rodc_control->critical = false;
385 return true;
388 static int objectclass_do_add(struct oc_context *ac)
390 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
391 struct ldb_request *add_req;
392 struct ldb_message_element *objectclass_element, *el;
393 struct ldb_message *msg;
394 const char *rdn_name = NULL;
395 char *value;
396 const struct dsdb_class *objectclass;
397 struct ldb_dn *objectcategory;
398 int32_t systemFlags = 0;
399 unsigned int i, j;
400 bool found;
401 int ret;
403 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
404 if (msg == NULL) {
405 return ldb_module_oom(ac->module);
408 /* Check if we have a valid parent - this check is needed since
409 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
410 if (ac->search_res == NULL) {
411 unsigned int instanceType;
413 /* An add operation on partition DNs without "NC-add" operation
414 * isn't allowed. */
415 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
417 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
418 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
419 ldb_dn_get_linearized(msg->dn));
420 return LDB_ERR_NO_SUCH_OBJECT;
423 /* Don't keep any error messages - we've to add a partition */
424 ldb_set_errstring(ldb, NULL);
425 } else {
426 /* Fix up the DN to be in the standard form, taking
427 * particular care to match the parent DN */
428 ret = fix_dn(ldb, msg,
429 ac->req->op.add.message->dn,
430 ac->search_res->message->dn,
431 &msg->dn);
432 if (ret != LDB_SUCCESS) {
433 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
434 ldb_dn_get_linearized(ac->req->op.add.message->dn));
435 return ret;
439 if (ac->schema != NULL) {
441 * Notice: by the normalization function call in "ldb_request()"
442 * case "LDB_ADD" we have always only *one* "objectClass"
443 * attribute at this stage!
446 objectclass_element = ldb_msg_find_element(msg, "objectClass");
447 if (!objectclass_element) {
448 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
449 ldb_dn_get_linearized(msg->dn));
450 return LDB_ERR_OBJECT_CLASS_VIOLATION;
452 if (objectclass_element->num_values == 0) {
453 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
454 ldb_dn_get_linearized(msg->dn));
455 return LDB_ERR_CONSTRAINT_VIOLATION;
458 /* Now do the sorting */
459 ret = dsdb_sort_objectClass_attr(ldb, ac->schema,
460 objectclass_element, msg,
461 objectclass_element);
462 if (ret != LDB_SUCCESS) {
463 return ret;
467 * Get the new top-most structural object class and check for
468 * unrelated structural classes
470 objectclass = dsdb_get_last_structural_class(ac->schema,
471 objectclass_element);
472 if (objectclass == NULL) {
473 ldb_asprintf_errstring(ldb,
474 "Failed to find a structural class for %s",
475 ldb_dn_get_linearized(msg->dn));
476 return LDB_ERR_UNWILLING_TO_PERFORM;
479 ret = check_unrelated_objectclasses(ac->module, ac->schema,
480 objectclass,
481 objectclass_element);
482 if (ret != LDB_SUCCESS) {
483 return ret;
486 rdn_name = ldb_dn_get_rdn_name(msg->dn);
487 if (rdn_name == NULL) {
488 return ldb_operr(ldb);
490 found = false;
491 for (i = 0; (!found) && (i < objectclass_element->num_values);
492 i++) {
493 const struct dsdb_class *tmp_class =
494 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
495 &objectclass_element->values[i]);
497 if (tmp_class == NULL) continue;
499 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
500 found = true;
502 if (!found) {
503 ldb_asprintf_errstring(ldb,
504 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
505 rdn_name, objectclass->lDAPDisplayName);
506 return LDB_ERR_NAMING_VIOLATION;
509 if (objectclass->systemOnly &&
510 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
511 !check_rodc_ntdsdsa_add(ac, objectclass)) {
512 ldb_asprintf_errstring(ldb,
513 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
514 objectclass->lDAPDisplayName,
515 ldb_dn_get_linearized(msg->dn));
516 return LDB_ERR_UNWILLING_TO_PERFORM;
519 if (ac->search_res && ac->search_res->message) {
520 struct ldb_message_element *oc_el
521 = ldb_msg_find_element(ac->search_res->message, "objectClass");
523 bool allowed_class = false;
524 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
525 const struct dsdb_class *sclass;
527 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
528 &oc_el->values[i]);
529 if (!sclass) {
530 /* We don't know this class? what is going on? */
531 continue;
533 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
534 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
535 allowed_class = true;
536 break;
541 if (!allowed_class) {
542 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
543 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
544 return LDB_ERR_NAMING_VIOLATION;
548 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
549 "objectCategory");
550 if (objectcategory == NULL) {
551 struct dsdb_extended_dn_store_format *dn_format =
552 talloc_get_type(ldb_module_get_private(ac->module),
553 struct dsdb_extended_dn_store_format);
554 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
555 /* Strip off extended components */
556 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
557 objectclass->defaultObjectCategory);
558 value = ldb_dn_alloc_linearized(msg, dn);
559 talloc_free(dn);
560 } else {
561 value = talloc_strdup(msg,
562 objectclass->defaultObjectCategory);
564 if (value == NULL) {
565 return ldb_module_oom(ac->module);
568 ret = ldb_msg_add_string(msg, "objectCategory", value);
569 if (ret != LDB_SUCCESS) {
570 return ret;
572 } else {
573 const struct dsdb_class *ocClass =
574 dsdb_class_by_cn_ldb_val(ac->schema,
575 ldb_dn_get_rdn_val(objectcategory));
576 if (ocClass != NULL) {
577 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
578 ocClass->defaultObjectCategory);
579 if (ldb_dn_compare(objectcategory, dn) != 0) {
580 ocClass = NULL;
583 talloc_free(objectcategory);
584 if (ocClass == NULL) {
585 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
586 ldb_dn_get_linearized(msg->dn));
587 return LDB_ERR_OBJECT_CLASS_VIOLATION;
591 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
592 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
593 "TRUE");
596 /* There are very special rules for systemFlags, see MS-ADTS
597 * MS-ADTS 3.1.1.5.2.4 */
599 el = ldb_msg_find_element(msg, "systemFlags");
600 if ((el != NULL) && (el->num_values > 1)) {
601 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
602 ldb_dn_get_linearized(msg->dn));
603 return LDB_ERR_CONSTRAINT_VIOLATION;
606 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
608 ldb_msg_remove_attr(msg, "systemFlags");
610 /* Only the following flags may be set by a client */
611 if (ldb_request_get_control(ac->req,
612 LDB_CONTROL_RELAX_OID) == NULL) {
613 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
614 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
615 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
616 | SYSTEM_FLAG_ATTR_IS_RDN );
619 /* But the last one ("ATTR_IS_RDN") is only allowed on
620 * "attributeSchema" objects. So truncate if it does not fit. */
621 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
622 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
625 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
626 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
627 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
628 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
629 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
630 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
631 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
632 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
633 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
634 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
635 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
636 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
637 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
639 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
641 if (el || systemFlags != 0) {
642 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
643 systemFlags);
644 if (ret != LDB_SUCCESS) {
645 return ret;
649 /* make sure that "isCriticalSystemObject" is not specified! */
650 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
651 if ((el != NULL) &&
652 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
653 ldb_set_errstring(ldb,
654 "objectclass: 'isCriticalSystemObject' must not be specified!");
655 return LDB_ERR_UNWILLING_TO_PERFORM;
659 ret = ldb_build_add_req(&add_req, ldb, ac,
660 msg,
661 ac->req->controls,
662 ac, oc_op_callback,
663 ac->req);
664 LDB_REQ_SET_LOCATION(add_req);
665 if (ret != LDB_SUCCESS) {
666 return ret;
669 /* perform the add */
670 return ldb_next_request(ac->module, add_req);
673 static int oc_modify_callback(struct ldb_request *req,
674 struct ldb_reply *ares);
675 static int objectclass_do_mod(struct oc_context *ac);
677 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
679 struct ldb_context *ldb = ldb_module_get_ctx(module);
680 struct ldb_message_element *objectclass_element;
681 struct ldb_message *msg;
682 struct ldb_request *down_req;
683 struct oc_context *ac;
684 bool oc_changes = false;
685 int ret;
687 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
689 /* do not manipulate our control entries */
690 if (ldb_dn_is_special(req->op.mod.message->dn)) {
691 return ldb_next_request(module, req);
694 /* As with the "real" AD we don't accept empty messages */
695 if (req->op.mod.message->num_elements == 0) {
696 ldb_set_errstring(ldb, "objectclass: modify message must have "
697 "elements/attributes!");
698 return LDB_ERR_UNWILLING_TO_PERFORM;
701 ac = oc_init_context(module, req);
702 if (ac == NULL) {
703 return ldb_operr(ldb);
706 /* Without schema, there isn't much to do here */
707 if (ac->schema == NULL) {
708 talloc_free(ac);
709 return ldb_next_request(module, req);
712 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
713 if (msg == NULL) {
714 return ldb_module_oom(ac->module);
717 /* For now change everything except the objectclasses */
719 objectclass_element = ldb_msg_find_element(msg, "objectClass");
720 if (objectclass_element != NULL) {
721 ldb_msg_remove_attr(msg, "objectClass");
722 oc_changes = true;
725 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
726 * only on application NCs - not on the default ones */
727 if (oc_changes &&
728 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
729 struct ldb_dn *nc_root;
731 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
732 &nc_root);
733 if (ret != LDB_SUCCESS) {
734 return ret;
737 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
738 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
739 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
740 ldb_set_errstring(ldb,
741 "objectclass: object class changes on objects under the standard name contexts not allowed!");
742 return LDB_ERR_UNWILLING_TO_PERFORM;
745 talloc_free(nc_root);
748 ret = ldb_build_mod_req(&down_req, ldb, ac,
749 msg,
750 req->controls, ac,
751 oc_changes ? oc_modify_callback : oc_op_callback,
752 req);
753 LDB_REQ_SET_LOCATION(down_req);
754 if (ret != LDB_SUCCESS) {
755 return ret;
758 return ldb_next_request(module, down_req);
761 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
763 static const char * const attrs[] = { "objectClass", NULL };
764 struct ldb_context *ldb;
765 struct ldb_request *search_req;
766 struct oc_context *ac;
767 int ret;
769 ac = talloc_get_type(req->context, struct oc_context);
770 ldb = ldb_module_get_ctx(ac->module);
772 if (!ares) {
773 return ldb_module_done(ac->req, NULL, NULL,
774 LDB_ERR_OPERATIONS_ERROR);
777 if (ares->type == LDB_REPLY_REFERRAL) {
778 return ldb_module_send_referral(ac->req, ares->referral);
781 if (ares->error != LDB_SUCCESS) {
782 return ldb_module_done(ac->req, ares->controls,
783 ares->response, ares->error);
786 if (ares->type != LDB_REPLY_DONE) {
787 talloc_free(ares);
788 return ldb_module_done(ac->req, NULL, NULL,
789 LDB_ERR_OPERATIONS_ERROR);
792 talloc_free(ares);
794 /* this looks up the real existing object for fetching some important
795 * information (objectclasses) */
796 ret = ldb_build_search_req(&search_req, ldb,
797 ac, ac->req->op.mod.message->dn,
798 LDB_SCOPE_BASE,
799 "(objectClass=*)",
800 attrs, NULL,
801 ac, get_search_callback,
802 ac->req);
803 LDB_REQ_SET_LOCATION(search_req);
804 if (ret != LDB_SUCCESS) {
805 return ldb_module_done(ac->req, NULL, NULL, ret);
808 ret = dsdb_request_add_controls(search_req,
809 DSDB_FLAG_AS_SYSTEM |
810 DSDB_SEARCH_SHOW_RECYCLED);
811 if (ret != LDB_SUCCESS) {
812 return ldb_module_done(ac->req, NULL, NULL, ret);
815 ac->step_fn = objectclass_do_mod;
817 ret = ldb_next_request(ac->module, search_req);
818 if (ret != LDB_SUCCESS) {
819 return ldb_module_done(ac->req, NULL, NULL, ret);
822 return LDB_SUCCESS;
825 static int objectclass_do_mod(struct oc_context *ac)
827 struct ldb_context *ldb;
828 struct ldb_request *mod_req;
829 struct ldb_message_element *oc_el_entry, *oc_el_change;
830 struct ldb_val *vals;
831 struct ldb_message *msg;
832 const struct dsdb_class *objectclass;
833 unsigned int i, j, k;
834 bool found;
835 int ret;
837 ldb = ldb_module_get_ctx(ac->module);
839 /* we should always have a valid entry when we enter here */
840 if (ac->search_res == NULL) {
841 return ldb_operr(ldb);
844 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
845 "objectClass");
846 if (oc_el_entry == NULL) {
847 /* existing entry without a valid object class? */
848 return ldb_operr(ldb);
851 /* use a new message structure */
852 msg = ldb_msg_new(ac);
853 if (msg == NULL) {
854 return ldb_module_oom(ac->module);
857 msg->dn = ac->req->op.mod.message->dn;
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) {
863 continue;
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 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
882 /* append the new object class value - code was
883 * copied from "ldb_msg_add_value" */
884 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
885 struct ldb_val,
886 oc_el_entry->num_values + 1);
887 if (vals == NULL) {
888 return ldb_module_oom(ac->module);
890 oc_el_entry->values = vals;
891 oc_el_entry->values[oc_el_entry->num_values] =
892 oc_el_change->values[i];
893 ++(oc_el_entry->num_values);
896 break;
898 case LDB_FLAG_MOD_REPLACE:
900 * In this case the new "oc_el_entry" is simply
901 * "oc_el_change"
903 oc_el_entry = oc_el_change;
905 break;
907 case LDB_FLAG_MOD_DELETE:
908 /* Merge the two message elements */
909 for (i = 0; i < oc_el_change->num_values; i++) {
910 found = false;
911 for (j = 0; j < oc_el_entry->num_values; j++) {
912 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
913 (char *)oc_el_entry->values[j].data) == 0) {
914 found = true;
915 /* delete the object class value
916 * - code was copied from
917 * "ldb_msg_remove_element" */
918 if (j != oc_el_entry->num_values - 1) {
919 memmove(&oc_el_entry->values[j],
920 &oc_el_entry->values[j+1],
921 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
923 --(oc_el_entry->num_values);
924 break;
927 if (!found) {
928 /* we cannot delete a not existing
929 * object class */
930 ldb_asprintf_errstring(ldb,
931 "objectclass: cannot delete this objectclass: '%.*s'!",
932 (int)oc_el_change->values[i].length,
933 (const char *)oc_el_change->values[i].data);
934 return LDB_ERR_NO_SUCH_ATTRIBUTE;
938 break;
941 /* Now do the sorting */
942 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, oc_el_entry,
943 msg, oc_el_entry);
944 if (ret != LDB_SUCCESS) {
945 return ret;
949 * Get the new top-most structural object class and check for
950 * unrelated structural classes
952 objectclass = dsdb_get_last_structural_class(ac->schema,
953 oc_el_entry);
954 if (objectclass == NULL) {
955 ldb_set_errstring(ldb,
956 "objectclass: cannot delete all structural objectclasses!");
957 return LDB_ERR_OBJECT_CLASS_VIOLATION;
960 /* Check for unrelated objectclasses */
961 ret = check_unrelated_objectclasses(ac->module, ac->schema,
962 objectclass,
963 oc_el_entry);
964 if (ret != LDB_SUCCESS) {
965 return ret;
969 /* Now add the new object class attribute to the change message */
970 ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
971 if (ret != LDB_SUCCESS) {
972 ldb_module_oom(ac->module);
973 return ret;
976 /* Now we have the real and definitive change left to do */
978 ret = ldb_build_mod_req(&mod_req, ldb, ac,
979 msg,
980 ac->req->controls,
981 ac, oc_op_callback,
982 ac->req);
983 LDB_REQ_SET_LOCATION(mod_req);
984 if (ret != LDB_SUCCESS) {
985 return ret;
988 return ldb_next_request(ac->module, mod_req);
991 static int objectclass_do_rename(struct oc_context *ac);
993 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
995 static const char * const attrs[] = { "objectClass", NULL };
996 struct ldb_context *ldb;
997 struct ldb_request *search_req;
998 struct oc_context *ac;
999 struct ldb_dn *parent_dn;
1000 int ret;
1002 ldb = ldb_module_get_ctx(module);
1004 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1006 /* do not manipulate our control entries */
1007 if (ldb_dn_is_special(req->op.rename.olddn)) {
1008 return ldb_next_request(module, req);
1011 ac = oc_init_context(module, req);
1012 if (ac == NULL) {
1013 return ldb_operr(ldb);
1016 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1017 if (parent_dn == NULL) {
1018 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1019 ldb_dn_get_linearized(req->op.rename.olddn));
1020 return LDB_ERR_NO_SUCH_OBJECT;
1023 /* this looks up the parent object for fetching some important
1024 * information (objectclasses, DN normalisation...) */
1025 ret = ldb_build_search_req(&search_req, ldb,
1026 ac, parent_dn, LDB_SCOPE_BASE,
1027 "(objectClass=*)",
1028 attrs, NULL,
1029 ac, get_search_callback,
1030 req);
1031 LDB_REQ_SET_LOCATION(search_req);
1032 if (ret != LDB_SUCCESS) {
1033 return ret;
1036 /* we have to add the show recycled control, as otherwise DRS
1037 deletes will be refused as we will think the target parent
1038 does not exist */
1039 ret = dsdb_request_add_controls(search_req,
1040 DSDB_FLAG_AS_SYSTEM |
1041 DSDB_SEARCH_SHOW_RECYCLED);
1042 if (ret != LDB_SUCCESS) {
1043 return ret;
1046 ac->step_fn = objectclass_do_rename;
1048 return ldb_next_request(ac->module, search_req);
1051 static int objectclass_do_rename2(struct oc_context *ac);
1053 static int objectclass_do_rename(struct oc_context *ac)
1055 static const char * const attrs[] = { "objectClass", NULL };
1056 struct ldb_context *ldb;
1057 struct ldb_request *search_req;
1058 int ret;
1060 ldb = ldb_module_get_ctx(ac->module);
1062 /* Check if we have a valid parent - this check is needed since
1063 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1064 if (ac->search_res == NULL) {
1065 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1066 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1067 return LDB_ERR_OTHER;
1070 /* now assign "search_res2" to the parent entry to have "search_res"
1071 * free for another lookup */
1072 ac->search_res2 = ac->search_res;
1073 ac->search_res = NULL;
1075 /* this looks up the real existing object for fetching some important
1076 * information (objectclasses) */
1077 ret = ldb_build_search_req(&search_req, ldb,
1078 ac, ac->req->op.rename.olddn,
1079 LDB_SCOPE_BASE,
1080 "(objectClass=*)",
1081 attrs, NULL,
1082 ac, get_search_callback,
1083 ac->req);
1084 LDB_REQ_SET_LOCATION(search_req);
1085 if (ret != LDB_SUCCESS) {
1086 return ret;
1089 ret = dsdb_request_add_controls(search_req,
1090 DSDB_FLAG_AS_SYSTEM |
1091 DSDB_SEARCH_SHOW_RECYCLED);
1092 if (ret != LDB_SUCCESS) {
1093 return ret;
1096 ac->step_fn = objectclass_do_rename2;
1098 return ldb_next_request(ac->module, search_req);
1101 static int objectclass_do_rename2(struct oc_context *ac)
1103 struct ldb_context *ldb;
1104 struct ldb_request *rename_req;
1105 struct ldb_dn *fixed_dn;
1106 int ret;
1108 ldb = ldb_module_get_ctx(ac->module);
1110 /* Check if we have a valid entry - this check is needed since
1111 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1112 if (ac->search_res == NULL) {
1113 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1114 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1115 return LDB_ERR_NO_SUCH_OBJECT;
1118 if (ac->schema != NULL) {
1119 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1120 const struct dsdb_class *objectclass;
1121 const char *rdn_name;
1122 bool allowed_class = false;
1123 unsigned int i, j;
1124 bool found;
1126 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1127 "objectClass");
1128 if (oc_el_entry == NULL) {
1129 /* existing entry without a valid object class? */
1130 return ldb_operr(ldb);
1132 objectclass = dsdb_get_last_structural_class(ac->schema,
1133 oc_el_entry);
1134 if (objectclass == NULL) {
1135 /* existing entry without a valid object class? */
1136 return ldb_operr(ldb);
1139 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1140 if (rdn_name == NULL) {
1141 return ldb_operr(ldb);
1143 found = false;
1144 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1145 const struct dsdb_class *tmp_class =
1146 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1147 &oc_el_entry->values[i]);
1149 if (tmp_class == NULL) continue;
1151 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1152 found = true;
1154 if (!found) {
1155 ldb_asprintf_errstring(ldb,
1156 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1157 rdn_name, objectclass->lDAPDisplayName);
1158 return LDB_ERR_UNWILLING_TO_PERFORM;
1161 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1162 "objectClass");
1163 if (oc_el_parent == NULL) {
1164 /* existing entry without a valid object class? */
1165 return ldb_operr(ldb);
1168 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1169 const struct dsdb_class *sclass;
1171 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1172 &oc_el_parent->values[i]);
1173 if (!sclass) {
1174 /* We don't know this class? what is going on? */
1175 continue;
1177 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1178 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1179 allowed_class = true;
1180 break;
1185 if (!allowed_class) {
1186 ldb_asprintf_errstring(ldb,
1187 "objectclass: structural objectClass %s is not a valid child class for %s",
1188 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1189 return LDB_ERR_NAMING_VIOLATION;
1193 /* Ensure we are not trying to rename it to be a child of itself */
1194 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1195 ac->req->op.rename.newdn) == 0) &&
1196 (ldb_dn_compare(ac->req->op.rename.olddn,
1197 ac->req->op.rename.newdn) != 0)) {
1198 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1199 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1200 return LDB_ERR_UNWILLING_TO_PERFORM;
1203 /* Fix up the DN to be in the standard form, taking
1204 * particular care to match the parent DN */
1205 ret = fix_dn(ldb, ac,
1206 ac->req->op.rename.newdn,
1207 ac->search_res2->message->dn,
1208 &fixed_dn);
1209 if (ret != LDB_SUCCESS) {
1210 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1211 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1212 return ret;
1216 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1217 ac->req->op.rename.olddn, fixed_dn,
1218 ac->req->controls,
1219 ac, oc_op_callback,
1220 ac->req);
1221 LDB_REQ_SET_LOCATION(rename_req);
1222 if (ret != LDB_SUCCESS) {
1223 return ret;
1226 /* perform the rename */
1227 return ldb_next_request(ac->module, rename_req);
1230 static int objectclass_do_delete(struct oc_context *ac);
1232 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1234 static const char * const attrs[] = { "nCName", "objectClass",
1235 "systemFlags",
1236 "isDeleted",
1237 "isCriticalSystemObject", NULL };
1238 struct ldb_context *ldb;
1239 struct ldb_request *search_req;
1240 struct oc_context *ac;
1241 int ret;
1243 ldb = ldb_module_get_ctx(module);
1245 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1247 /* do not manipulate our control entries */
1248 if (ldb_dn_is_special(req->op.del.dn)) {
1249 return ldb_next_request(module, req);
1252 /* Bypass the constraint checks when we do have the "RELAX" control
1253 * set. */
1254 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1255 return ldb_next_request(module, req);
1258 ac = oc_init_context(module, req);
1259 if (ac == NULL) {
1260 return ldb_operr(ldb);
1263 /* this looks up the entry object for fetching some important
1264 * information (object classes, system flags...) */
1265 ret = ldb_build_search_req(&search_req, ldb,
1266 ac, req->op.del.dn, LDB_SCOPE_BASE,
1267 "(objectClass=*)",
1268 attrs, NULL,
1269 ac, get_search_callback,
1270 req);
1271 LDB_REQ_SET_LOCATION(search_req);
1272 if (ret != LDB_SUCCESS) {
1273 return ret;
1276 ret = dsdb_request_add_controls(search_req,
1277 DSDB_FLAG_AS_SYSTEM |
1278 DSDB_SEARCH_SHOW_RECYCLED);
1279 if (ret != LDB_SUCCESS) {
1280 return ret;
1283 ac->step_fn = objectclass_do_delete;
1285 return ldb_next_request(ac->module, search_req);
1288 static int objectclass_do_delete(struct oc_context *ac)
1290 struct ldb_context *ldb;
1291 struct ldb_dn *dn;
1292 int32_t systemFlags;
1293 bool isCriticalSystemObject;
1294 int ret;
1296 ldb = ldb_module_get_ctx(ac->module);
1298 /* Check if we have a valid entry - this check is needed since
1299 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1300 if (ac->search_res == NULL) {
1301 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1302 ldb_dn_get_linearized(ac->req->op.del.dn));
1303 return LDB_ERR_NO_SUCH_OBJECT;
1306 /* DC's ntDSDSA object */
1307 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb, ac)) == 0) {
1308 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1309 ldb_dn_get_linearized(ac->req->op.del.dn));
1310 return LDB_ERR_UNWILLING_TO_PERFORM;
1313 /* DC's rIDSet object */
1314 /* Perform this check only when it does exist - this is needed in order
1315 * to don't let existing provisions break. */
1316 ret = samdb_rid_set_dn(ldb, ac, &dn);
1317 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1318 return ret;
1320 if (ret == LDB_SUCCESS) {
1321 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1322 talloc_free(dn);
1323 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1324 ldb_dn_get_linearized(ac->req->op.del.dn));
1325 return LDB_ERR_UNWILLING_TO_PERFORM;
1327 talloc_free(dn);
1330 /* Only trusted request from system account are allowed to delete
1331 * deleted objects.
1333 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1334 (ldb_req_is_untrusted(ac->req) ||
1335 !dsdb_module_am_system(ac->module))) {
1336 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1337 ldb_dn_get_linearized(ac->req->op.del.dn));
1338 return LDB_ERR_UNWILLING_TO_PERFORM;
1341 /* crossRef objects regarding config, schema and default domain NCs */
1342 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1343 "crossRef") != NULL) {
1344 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1345 "nCName");
1346 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1347 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1348 talloc_free(dn);
1350 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1351 ldb_dn_get_linearized(ac->req->op.del.dn));
1352 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1354 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1355 talloc_free(dn);
1357 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1358 ldb_dn_get_linearized(ac->req->op.del.dn));
1359 return LDB_ERR_UNWILLING_TO_PERFORM;
1361 talloc_free(dn);
1364 /* systemFlags */
1366 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1367 "systemFlags", 0);
1368 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1369 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1370 ldb_dn_get_linearized(ac->req->op.del.dn));
1371 return LDB_ERR_UNWILLING_TO_PERFORM;
1374 /* isCriticalSystemObject - but this only applies on tree delete
1375 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1376 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1377 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1378 "isCriticalSystemObject", false);
1379 if (isCriticalSystemObject) {
1381 * Following the explaination from Microsoft
1382 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1383 * "I finished the investigation on this behavior.
1384 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1385 * every object in the tree will be checked to see if it has isCriticalSystemObject
1386 * set to TRUE, including the root node on which the delete operation is performed
1387 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1388 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1389 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1390 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1393 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1394 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1395 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1396 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1397 ldb_asprintf_errstring(ldb,
1398 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1399 ldb_dn_get_linearized(ac->req->op.del.dn));
1400 return LDB_ERR_UNWILLING_TO_PERFORM;
1405 return ldb_next_request(ac->module, ac->req);
1408 static int objectclass_init(struct ldb_module *module)
1410 struct ldb_context *ldb = ldb_module_get_ctx(module);
1411 int ret;
1413 /* Init everything else */
1414 ret = ldb_next_init(module);
1415 if (ret != LDB_SUCCESS) {
1416 return ret;
1419 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1420 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1422 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1423 if (ret != LDB_SUCCESS) {
1424 ldb_debug(ldb, LDB_DEBUG_ERROR,
1425 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1426 return ldb_operr(ldb);
1429 return ret;
1432 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1433 .name = "objectclass",
1434 .add = objectclass_add,
1435 .modify = objectclass_modify,
1436 .rename = objectclass_rename,
1437 .del = objectclass_delete,
1438 .init_context = objectclass_init
1441 int ldb_objectclass_module_init(const char *version)
1443 LDB_MODULE_CHECK_VERSION(version);
1444 return ldb_register_module(&ldb_objectclass_module_ops);