s4:objectclass LDB module - fix up the sorting in respect to structural or 88 objectc...
[Samba/bjacke.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blobb66b4d7a5f4f8f10199af62f6149bfd28bf31e32
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 "util/dlinklist.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "librpc/ndr/libndr.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "libcli/security/security.h"
45 #include "auth/auth.h"
46 #include "param/param.h"
47 #include "../libds/common/flags.h"
48 #include "dsdb/samdb/ldb_modules/schema.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
51 struct oc_context {
53 struct ldb_module *module;
54 struct ldb_request *req;
55 const struct dsdb_schema *schema;
57 struct ldb_reply *search_res;
58 struct ldb_reply *search_res2;
60 int (*step_fn)(struct oc_context *);
63 struct class_list {
64 struct class_list *prev, *next;
65 const struct dsdb_class *objectclass;
68 static struct oc_context *oc_init_context(struct ldb_module *module,
69 struct ldb_request *req)
71 struct ldb_context *ldb;
72 struct oc_context *ac;
74 ldb = ldb_module_get_ctx(module);
76 ac = talloc_zero(req, struct oc_context);
77 if (ac == NULL) {
78 ldb_oom(ldb);
79 return NULL;
82 ac->module = module;
83 ac->req = req;
84 ac->schema = dsdb_get_schema(ldb, ac);
86 return ac;
89 static int objectclass_do_add(struct oc_context *ac);
91 /* Sort objectClasses into correct order, and validate that all
92 * objectClasses specified actually exist in the schema
95 static int objectclass_sort(struct ldb_module *module,
96 const struct dsdb_schema *schema,
97 TALLOC_CTX *mem_ctx,
98 struct ldb_message_element *objectclass_element,
99 struct class_list **sorted_out)
101 struct ldb_context *ldb;
102 unsigned int i, lowest;
103 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL,
104 *poss_parent = NULL, *new_parent = NULL,
105 *current_lowest = NULL, *current_lowest_struct = NULL;
107 ldb = ldb_module_get_ctx(module);
109 /* DESIGN:
111 * We work on 4 different 'bins' (implemented here as linked lists):
113 * * sorted: the eventual list, in the order we wish to push
114 * into the database. This is the only ordered list.
116 * * parent_class: The current parent class 'bin' we are
117 * trying to find subclasses for
119 * * subclass: The subclasses we have found so far
121 * * unsorted: The remaining objectClasses
123 * The process is a matter of filtering objectClasses up from
124 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
126 * We start with 'top' (found and promoted to parent_class
127 * initially). Then we find (in unsorted) all the direct
128 * subclasses of 'top'. parent_classes is concatenated onto
129 * the end of 'sorted', and subclass becomes the list in
130 * parent_class.
132 * We then repeat, until we find no more subclasses. Any left
133 * over classes are added to the end.
137 /* Firstly, dump all the objectClass elements into the
138 * unsorted bin, except for 'top', which is special */
139 for (i=0; i < objectclass_element->num_values; i++) {
140 current = talloc(mem_ctx, struct class_list);
141 if (!current) {
142 return ldb_oom(ldb);
144 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
145 if (!current->objectclass) {
146 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
147 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
148 /* This looks weird, but windows apparently returns this for invalid objectClass values */
149 return LDB_ERR_NO_SUCH_ATTRIBUTE;
150 } else if (current->objectclass->isDefunct) {
151 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
152 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
153 /* This looks weird, but windows apparently returns this for invalid objectClass values */
154 return LDB_ERR_NO_SUCH_ATTRIBUTE;
157 /* Don't add top to list, we will do that later */
158 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
159 DLIST_ADD_END(unsorted, current, struct class_list *);
163 /* Add top here, to prevent duplicates */
164 current = talloc(mem_ctx, struct class_list);
165 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
166 DLIST_ADD_END(sorted, current, struct class_list *);
168 /* If we don't have a schema yet, then just merge the lists again */
169 if (!schema) {
170 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
171 *sorted_out = sorted;
172 return LDB_SUCCESS;
175 /* For each object: find parent chain */
176 for (current = unsorted; current != NULL; current = current->next) {
177 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
178 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
179 break;
182 /* If we didn't get to the end of the list, we need to add this parent */
183 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
184 continue;
187 new_parent = talloc(mem_ctx, struct class_list);
188 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
189 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
192 /* For each object: order by hierarchy */
193 while (unsorted != NULL) {
194 lowest = UINT_MAX;
195 current_lowest = current_lowest_struct = NULL;
196 for (current = unsorted; current != NULL; current = current->next) {
197 if (current->objectclass->subClass_order <= lowest) {
199 * According to MS-ADTS 3.1.1.1.4 structural
200 * and 88 object classes are always listed after
201 * the other class types in a subclass hierarchy
203 if (current->objectclass->objectClassCategory > 1) {
204 current_lowest = current;
205 } else {
206 current_lowest_struct = current;
208 lowest = current->objectclass->subClass_order;
211 if (current_lowest == NULL) {
212 current_lowest = current_lowest_struct;
215 if (current_lowest != NULL) {
216 DLIST_REMOVE(unsorted,current_lowest);
217 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
221 *sorted_out = sorted;
222 return LDB_SUCCESS;
226 * This checks if we have unrelated object classes in our entry's "objectClass"
227 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
228 * or two or more disjunct structural ones.
229 * If one of these conditions are true, blame.
231 static int check_unrelated_objectclasses(struct ldb_module *module,
232 const struct dsdb_schema *schema,
233 const struct dsdb_class *struct_objectclass,
234 struct ldb_message_element *objectclass_element)
236 struct ldb_context *ldb = ldb_module_get_ctx(module);
237 unsigned int i;
238 bool found;
240 if (schema == NULL) {
241 return LDB_SUCCESS;
244 for (i = 0; i < objectclass_element->num_values; i++) {
245 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
246 &objectclass_element->values[i]);
247 const struct dsdb_class *tmp_class2 = struct_objectclass;
249 /* Pointer comparison can be used due to the same schema str. */
250 if (tmp_class == NULL ||
251 tmp_class == struct_objectclass ||
252 tmp_class->objectClassCategory > 2 ||
253 ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
254 continue;
257 found = false;
258 while (!found &&
259 ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
260 tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
261 tmp_class2->subClassOf);
262 if (tmp_class2 == tmp_class) {
263 found = true;
266 if (found) {
267 continue;
270 ldb_asprintf_errstring(ldb,
271 "objectclass: the objectclass '%s' seems to be unrelated to the entry!",
272 tmp_class->lDAPDisplayName);
273 return LDB_ERR_OBJECT_CLASS_VIOLATION;
276 return LDB_SUCCESS;
279 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
281 struct ldb_context *ldb;
282 struct oc_context *ac;
283 int ret;
285 ac = talloc_get_type(req->context, struct oc_context);
286 ldb = ldb_module_get_ctx(ac->module);
288 if (!ares) {
289 return ldb_module_done(ac->req, NULL, NULL,
290 LDB_ERR_OPERATIONS_ERROR);
292 if (ares->error != LDB_SUCCESS &&
293 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
294 return ldb_module_done(ac->req, ares->controls,
295 ares->response, ares->error);
298 ldb_reset_err_string(ldb);
300 switch (ares->type) {
301 case LDB_REPLY_ENTRY:
302 if (ac->search_res != NULL) {
303 ldb_set_errstring(ldb, "Too many results");
304 talloc_free(ares);
305 return ldb_module_done(ac->req, NULL, NULL,
306 LDB_ERR_OPERATIONS_ERROR);
309 ac->search_res = talloc_steal(ac, ares);
310 break;
312 case LDB_REPLY_REFERRAL:
313 /* ignore */
314 talloc_free(ares);
315 break;
317 case LDB_REPLY_DONE:
318 talloc_free(ares);
319 ret = ac->step_fn(ac);
320 if (ret != LDB_SUCCESS) {
321 return ldb_module_done(ac->req, NULL, NULL, ret);
323 break;
326 return LDB_SUCCESS;
329 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
331 struct oc_context *ac;
333 ac = talloc_get_type(req->context, struct oc_context);
335 if (!ares) {
336 return ldb_module_done(ac->req, NULL, NULL,
337 LDB_ERR_OPERATIONS_ERROR);
340 if (ares->type == LDB_REPLY_REFERRAL) {
341 return ldb_module_send_referral(ac->req, ares->referral);
344 if (ares->error != LDB_SUCCESS) {
345 return ldb_module_done(ac->req, ares->controls,
346 ares->response, ares->error);
349 if (ares->type != LDB_REPLY_DONE) {
350 talloc_free(ares);
351 return ldb_module_done(ac->req, NULL, NULL,
352 LDB_ERR_OPERATIONS_ERROR);
355 return ldb_module_done(ac->req, ares->controls,
356 ares->response, ares->error);
359 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
361 This should mean that if the parent is:
362 CN=Users,DC=samba,DC=example,DC=com
363 and a proposed child is
364 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
366 The resulting DN should be:
368 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
371 static int fix_dn(struct ldb_context *ldb,
372 TALLOC_CTX *mem_ctx,
373 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
374 struct ldb_dn **fixed_dn)
376 char *upper_rdn_attr;
377 const struct ldb_val *rdn_val;
379 /* Fix up the DN to be in the standard form, taking particular care to
380 * match the parent DN */
381 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
382 if (*fixed_dn == NULL) {
383 return ldb_oom(ldb);
386 /* We need the attribute name in upper case */
387 upper_rdn_attr = strupper_talloc(*fixed_dn,
388 ldb_dn_get_rdn_name(newdn));
389 if (upper_rdn_attr == NULL) {
390 return ldb_oom(ldb);
393 /* Create a new child */
394 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
395 return ldb_operr(ldb);
398 rdn_val = ldb_dn_get_rdn_val(newdn);
399 if (rdn_val == NULL) {
400 return ldb_operr(ldb);
403 #if 0
404 /* the rules for rDN length constraints are more complex than
405 this. Until we understand them we need to leave this
406 constraint out. Otherwise we break replication, as windows
407 does sometimes send us rDNs longer than 64 */
408 if (!rdn_val || rdn_val->length > 64) {
409 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
411 #endif
414 /* And replace it with CN=foo (we need the attribute in upper case) */
415 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
419 static int objectclass_do_add(struct oc_context *ac);
421 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
423 struct ldb_context *ldb;
424 struct ldb_request *search_req;
425 struct oc_context *ac;
426 struct ldb_dn *parent_dn;
427 const struct ldb_val *val;
428 int ret;
429 static const char * const parent_attrs[] = { "objectClass", NULL };
431 ldb = ldb_module_get_ctx(module);
433 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
435 /* do not manipulate our control entries */
436 if (ldb_dn_is_special(req->op.add.message->dn)) {
437 return ldb_next_request(module, req);
440 /* An add operation on the basedn without "NC-add" operation isn't
441 * allowed. */
442 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
443 unsigned int instanceType;
445 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
446 "instanceType", 0);
447 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
448 char *referral_uri;
449 /* When we are trying to readd the root basedn then
450 * this is denied, but with an interesting mechanism:
451 * there is generated a referral with the last
452 * component value as hostname. */
453 val = ldb_dn_get_component_val(req->op.add.message->dn,
454 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
455 if (val == NULL) {
456 return ldb_operr(ldb);
458 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
459 ldb_dn_get_linearized(req->op.add.message->dn));
460 if (referral_uri == NULL) {
461 return ldb_module_oom(module);
464 return ldb_module_send_referral(req, referral_uri);
468 ac = oc_init_context(module, req);
469 if (ac == NULL) {
470 return ldb_operr(ldb);
473 /* If there isn't a parent, just go on to the add processing */
474 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
475 return objectclass_do_add(ac);
478 /* get copy of parent DN */
479 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
480 if (parent_dn == NULL) {
481 return ldb_operr(ldb);
484 ret = ldb_build_search_req(&search_req, ldb,
485 ac, parent_dn, LDB_SCOPE_BASE,
486 "(objectClass=*)", parent_attrs,
487 NULL,
488 ac, get_search_callback,
489 req);
490 LDB_REQ_SET_LOCATION(search_req);
491 if (ret != LDB_SUCCESS) {
492 return ret;
495 ac->step_fn = objectclass_do_add;
497 return ldb_next_request(ac->module, search_req);
502 check if this is a special RODC nTDSDSA add
504 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
505 const struct dsdb_class *objectclass)
507 struct ldb_control *rodc_control;
509 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
510 return false;
512 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
513 if (!rodc_control) {
514 return false;
517 rodc_control->critical = false;
518 return true;
521 static int objectclass_do_add(struct oc_context *ac)
523 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
524 struct ldb_request *add_req;
525 struct ldb_message_element *objectclass_element, *el;
526 struct ldb_message *msg;
527 TALLOC_CTX *mem_ctx;
528 struct class_list *sorted, *current;
529 const char *rdn_name = NULL;
530 char *value;
531 const struct dsdb_class *objectclass;
532 struct ldb_dn *objectcategory;
533 int32_t systemFlags = 0;
534 unsigned int i, j;
535 bool found;
536 int ret;
538 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
539 if (msg == NULL) {
540 return ldb_module_oom(ac->module);
543 /* Check if we have a valid parent - this check is needed since
544 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
545 if (ac->search_res == NULL) {
546 unsigned int instanceType;
548 /* An add operation on partition DNs without "NC-add" operation
549 * isn't allowed. */
550 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
552 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
553 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
554 ldb_dn_get_linearized(msg->dn));
555 return LDB_ERR_NO_SUCH_OBJECT;
558 /* Don't keep any error messages - we've to add a partition */
559 ldb_set_errstring(ldb, NULL);
560 } else {
561 /* Fix up the DN to be in the standard form, taking
562 * particular care to match the parent DN */
563 ret = fix_dn(ldb, msg,
564 ac->req->op.add.message->dn,
565 ac->search_res->message->dn,
566 &msg->dn);
567 if (ret != LDB_SUCCESS) {
568 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
569 ldb_dn_get_linearized(ac->req->op.add.message->dn));
570 return ret;
574 if (ac->schema != NULL) {
575 objectclass_element = ldb_msg_find_element(msg, "objectClass");
576 if (!objectclass_element) {
577 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
578 ldb_dn_get_linearized(msg->dn));
579 return LDB_ERR_OBJECT_CLASS_VIOLATION;
581 if (objectclass_element->num_values == 0) {
582 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
583 ldb_dn_get_linearized(msg->dn));
584 return LDB_ERR_CONSTRAINT_VIOLATION;
587 mem_ctx = talloc_new(ac);
588 if (mem_ctx == NULL) {
589 return ldb_module_oom(ac->module);
592 /* Here we do now get the "objectClass" list from the
593 * database. */
594 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
595 objectclass_element, &sorted);
596 if (ret != LDB_SUCCESS) {
597 talloc_free(mem_ctx);
598 return ret;
601 ldb_msg_remove_element(msg, objectclass_element);
603 /* Well, now we shouldn't find any additional "objectClass"
604 * message element (required by the AD specification). */
605 objectclass_element = ldb_msg_find_element(msg, "objectClass");
606 if (objectclass_element != NULL) {
607 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
608 ldb_dn_get_linearized(msg->dn));
609 talloc_free(mem_ctx);
610 return LDB_ERR_OBJECT_CLASS_VIOLATION;
613 /* We must completely replace the existing objectClass entry,
614 * because we need it sorted. */
615 ret = ldb_msg_add_empty(msg, "objectClass", 0,
616 &objectclass_element);
617 if (ret != LDB_SUCCESS) {
618 talloc_free(mem_ctx);
619 return ret;
622 /* Move from the linked list back into an ldb msg */
623 for (current = sorted; current; current = current->next) {
624 const char *objectclass_name = current->objectclass->lDAPDisplayName;
626 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
627 if (ret != LDB_SUCCESS) {
628 ldb_set_errstring(ldb,
629 "objectclass: could not re-add sorted "
630 "objectclass to modify msg");
631 talloc_free(mem_ctx);
632 return ret;
636 talloc_free(mem_ctx);
638 /* Make sure its valid to add an object of this type */
639 objectclass = get_last_structural_class(ac->schema,
640 objectclass_element, ac->req);
641 if(objectclass == NULL) {
642 ldb_asprintf_errstring(ldb,
643 "Failed to find a structural class for %s",
644 ldb_dn_get_linearized(msg->dn));
645 return LDB_ERR_UNWILLING_TO_PERFORM;
648 ret = check_unrelated_objectclasses(ac->module, ac->schema,
649 objectclass,
650 objectclass_element);
651 if (ret != LDB_SUCCESS) {
652 return ret;
655 rdn_name = ldb_dn_get_rdn_name(msg->dn);
656 if (rdn_name == NULL) {
657 return ldb_operr(ldb);
659 found = false;
660 for (i = 0; (!found) && (i < objectclass_element->num_values);
661 i++) {
662 const struct dsdb_class *tmp_class =
663 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
664 &objectclass_element->values[i]);
666 if (tmp_class == NULL) continue;
668 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
669 found = true;
671 if (!found) {
672 ldb_asprintf_errstring(ldb,
673 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
674 rdn_name, objectclass->lDAPDisplayName);
675 return LDB_ERR_NAMING_VIOLATION;
678 if (objectclass->systemOnly &&
679 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
680 !check_rodc_ntdsdsa_add(ac, objectclass)) {
681 ldb_asprintf_errstring(ldb,
682 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
683 objectclass->lDAPDisplayName,
684 ldb_dn_get_linearized(msg->dn));
685 return LDB_ERR_UNWILLING_TO_PERFORM;
688 if (ac->search_res && ac->search_res->message) {
689 struct ldb_message_element *oc_el
690 = ldb_msg_find_element(ac->search_res->message, "objectClass");
692 bool allowed_class = false;
693 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
694 const struct dsdb_class *sclass;
696 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
697 &oc_el->values[i]);
698 if (!sclass) {
699 /* We don't know this class? what is going on? */
700 continue;
702 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
703 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
704 allowed_class = true;
705 break;
710 if (!allowed_class) {
711 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
712 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
713 return LDB_ERR_NAMING_VIOLATION;
717 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
718 "objectCategory");
719 if (objectcategory == NULL) {
720 struct dsdb_extended_dn_store_format *dn_format =
721 talloc_get_type(ldb_module_get_private(ac->module),
722 struct dsdb_extended_dn_store_format);
723 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
724 /* Strip off extended components */
725 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
726 objectclass->defaultObjectCategory);
727 value = ldb_dn_alloc_linearized(msg, dn);
728 talloc_free(dn);
729 } else {
730 value = talloc_strdup(msg,
731 objectclass->defaultObjectCategory);
733 if (value == NULL) {
734 return ldb_module_oom(ac->module);
737 ret = ldb_msg_add_string(msg, "objectCategory", value);
738 if (ret != LDB_SUCCESS) {
739 return ret;
741 } else {
742 const struct dsdb_class *ocClass =
743 dsdb_class_by_cn_ldb_val(ac->schema,
744 ldb_dn_get_rdn_val(objectcategory));
745 if (ocClass != NULL) {
746 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
747 ocClass->defaultObjectCategory);
748 if (ldb_dn_compare(objectcategory, dn) != 0) {
749 ocClass = NULL;
752 talloc_free(objectcategory);
753 if (ocClass == NULL) {
754 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
755 ldb_dn_get_linearized(msg->dn));
756 return LDB_ERR_OBJECT_CLASS_VIOLATION;
760 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
761 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
762 "TRUE");
765 /* There are very special rules for systemFlags, see MS-ADTS
766 * MS-ADTS 3.1.1.5.2.4 */
768 el = ldb_msg_find_element(msg, "systemFlags");
769 if ((el != NULL) && (el->num_values > 1)) {
770 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
771 ldb_dn_get_linearized(msg->dn));
772 return LDB_ERR_CONSTRAINT_VIOLATION;
775 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
777 ldb_msg_remove_attr(msg, "systemFlags");
779 /* Only the following flags may be set by a client */
780 if (ldb_request_get_control(ac->req,
781 LDB_CONTROL_RELAX_OID) == NULL) {
782 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
783 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
784 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
785 | SYSTEM_FLAG_ATTR_IS_RDN );
788 /* But the last one ("ATTR_IS_RDN") is only allowed on
789 * "attributeSchema" objects. So truncate if it does not fit. */
790 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
791 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
794 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
795 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
796 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
797 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
798 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
799 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
800 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
801 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
802 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
803 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
804 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
805 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
806 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
808 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
810 if (el || systemFlags != 0) {
811 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
812 systemFlags);
813 if (ret != LDB_SUCCESS) {
814 return ret;
818 /* make sure that "isCriticalSystemObject" is not specified! */
819 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
820 if ((el != NULL) &&
821 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
822 ldb_set_errstring(ldb,
823 "objectclass: 'isCriticalSystemObject' must not be specified!");
824 return LDB_ERR_UNWILLING_TO_PERFORM;
828 ret = ldb_build_add_req(&add_req, ldb, ac,
829 msg,
830 ac->req->controls,
831 ac, oc_op_callback,
832 ac->req);
833 LDB_REQ_SET_LOCATION(add_req);
834 if (ret != LDB_SUCCESS) {
835 return ret;
838 /* perform the add */
839 return ldb_next_request(ac->module, add_req);
842 static int oc_modify_callback(struct ldb_request *req,
843 struct ldb_reply *ares);
844 static int objectclass_do_mod(struct oc_context *ac);
846 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
848 struct ldb_context *ldb = ldb_module_get_ctx(module);
849 struct ldb_message_element *objectclass_element;
850 struct ldb_message *msg;
851 struct ldb_request *down_req;
852 struct oc_context *ac;
853 bool oc_changes = false;
854 int ret;
856 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
858 /* do not manipulate our control entries */
859 if (ldb_dn_is_special(req->op.mod.message->dn)) {
860 return ldb_next_request(module, req);
863 /* As with the "real" AD we don't accept empty messages */
864 if (req->op.mod.message->num_elements == 0) {
865 ldb_set_errstring(ldb, "objectclass: modify message must have "
866 "elements/attributes!");
867 return LDB_ERR_UNWILLING_TO_PERFORM;
870 ac = oc_init_context(module, req);
871 if (ac == NULL) {
872 return ldb_operr(ldb);
875 /* Without schema, there isn't much to do here */
876 if (ac->schema == NULL) {
877 talloc_free(ac);
878 return ldb_next_request(module, req);
881 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
882 if (msg == NULL) {
883 return ldb_module_oom(ac->module);
886 /* For now change everything except the objectclasses */
888 objectclass_element = ldb_msg_find_element(msg, "objectClass");
889 if (objectclass_element != NULL) {
890 ldb_msg_remove_attr(msg, "objectClass");
891 oc_changes = true;
894 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
895 * only on application NCs - not on the default ones */
896 if (oc_changes &&
897 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
898 struct ldb_dn *nc_root;
900 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
901 &nc_root);
902 if (ret != LDB_SUCCESS) {
903 return ret;
906 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
907 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
908 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
909 ldb_set_errstring(ldb,
910 "objectclass: object class changes on objects under the standard name contexts not allowed!");
911 return LDB_ERR_UNWILLING_TO_PERFORM;
914 talloc_free(nc_root);
917 ret = ldb_build_mod_req(&down_req, ldb, ac,
918 msg,
919 req->controls, ac,
920 oc_changes ? oc_modify_callback : oc_op_callback,
921 req);
922 LDB_REQ_SET_LOCATION(down_req);
923 if (ret != LDB_SUCCESS) {
924 return ret;
927 return ldb_next_request(module, down_req);
930 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
932 static const char * const attrs[] = { "objectClass", NULL };
933 struct ldb_context *ldb;
934 struct ldb_request *search_req;
935 struct oc_context *ac;
936 int ret;
938 ac = talloc_get_type(req->context, struct oc_context);
939 ldb = ldb_module_get_ctx(ac->module);
941 if (!ares) {
942 return ldb_module_done(ac->req, NULL, NULL,
943 LDB_ERR_OPERATIONS_ERROR);
946 if (ares->type == LDB_REPLY_REFERRAL) {
947 return ldb_module_send_referral(ac->req, ares->referral);
950 if (ares->error != LDB_SUCCESS) {
951 return ldb_module_done(ac->req, ares->controls,
952 ares->response, ares->error);
955 if (ares->type != LDB_REPLY_DONE) {
956 talloc_free(ares);
957 return ldb_module_done(ac->req, NULL, NULL,
958 LDB_ERR_OPERATIONS_ERROR);
961 talloc_free(ares);
963 /* this looks up the real existing object for fetching some important
964 * information (objectclasses) */
965 ret = ldb_build_search_req(&search_req, ldb,
966 ac, ac->req->op.mod.message->dn,
967 LDB_SCOPE_BASE,
968 "(objectClass=*)",
969 attrs, NULL,
970 ac, get_search_callback,
971 ac->req);
972 LDB_REQ_SET_LOCATION(search_req);
973 if (ret != LDB_SUCCESS) {
974 return ldb_module_done(ac->req, NULL, NULL, ret);
977 ac->step_fn = objectclass_do_mod;
979 ret = ldb_next_request(ac->module, search_req);
980 if (ret != LDB_SUCCESS) {
981 return ldb_module_done(ac->req, NULL, NULL, ret);
984 return LDB_SUCCESS;
987 static int objectclass_do_mod(struct oc_context *ac)
989 struct ldb_context *ldb;
990 struct ldb_request *mod_req;
991 struct ldb_message_element *oc_el_entry, *oc_el_change;
992 struct ldb_val *vals;
993 struct ldb_message *msg;
994 TALLOC_CTX *mem_ctx;
995 struct class_list *sorted, *current;
996 const struct dsdb_class *objectclass;
997 unsigned int i, j, k;
998 bool found;
999 int ret;
1001 ldb = ldb_module_get_ctx(ac->module);
1003 /* we should always have a valid entry when we enter here */
1004 if (ac->search_res == NULL) {
1005 return ldb_operr(ldb);
1008 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1009 "objectClass");
1010 if (oc_el_entry == NULL) {
1011 /* existing entry without a valid object class? */
1012 return ldb_operr(ldb);
1015 /* use a new message structure */
1016 msg = ldb_msg_new(ac);
1017 if (msg == NULL) {
1018 return ldb_module_oom(ac->module);
1021 msg->dn = ac->req->op.mod.message->dn;
1023 mem_ctx = talloc_new(ac);
1024 if (mem_ctx == NULL) {
1025 return ldb_module_oom(ac->module);
1028 /* We've to walk over all "objectClass" message elements */
1029 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
1030 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
1031 "objectClass") != 0) {
1032 continue;
1035 oc_el_change = &ac->req->op.mod.message->elements[k];
1037 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
1038 case LDB_FLAG_MOD_ADD:
1039 /* Merge the two message elements */
1040 for (i = 0; i < oc_el_change->num_values; i++) {
1041 for (j = 0; j < oc_el_entry->num_values; j++) {
1042 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1043 (char *)oc_el_entry->values[j].data) == 0) {
1044 ldb_asprintf_errstring(ldb,
1045 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1046 (int)oc_el_change->values[i].length,
1047 (const char *)oc_el_change->values[i].data);
1048 talloc_free(mem_ctx);
1049 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1052 /* append the new object class value - code was
1053 * copied from "ldb_msg_add_value" */
1054 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1055 struct ldb_val,
1056 oc_el_entry->num_values + 1);
1057 if (vals == NULL) {
1058 talloc_free(mem_ctx);
1059 return ldb_module_oom(ac->module);
1061 oc_el_entry->values = vals;
1062 oc_el_entry->values[oc_el_entry->num_values] =
1063 oc_el_change->values[i];
1064 ++(oc_el_entry->num_values);
1067 break;
1069 case LDB_FLAG_MOD_REPLACE:
1071 * In this case the new "oc_el_entry" is simply
1072 * "oc_el_change"
1074 oc_el_entry = oc_el_change;
1076 break;
1078 case LDB_FLAG_MOD_DELETE:
1079 /* Merge the two message elements */
1080 for (i = 0; i < oc_el_change->num_values; i++) {
1081 found = false;
1082 for (j = 0; j < oc_el_entry->num_values; j++) {
1083 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1084 (char *)oc_el_entry->values[j].data) == 0) {
1085 found = true;
1086 /* delete the object class value
1087 * - code was copied from
1088 * "ldb_msg_remove_element" */
1089 if (j != oc_el_entry->num_values - 1) {
1090 memmove(&oc_el_entry->values[j],
1091 &oc_el_entry->values[j+1],
1092 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1094 --(oc_el_entry->num_values);
1095 break;
1098 if (!found) {
1099 /* we cannot delete a not existing
1100 * object class */
1101 ldb_asprintf_errstring(ldb,
1102 "objectclass: cannot delete this objectclass: '%.*s'!",
1103 (int)oc_el_change->values[i].length,
1104 (const char *)oc_el_change->values[i].data);
1105 talloc_free(mem_ctx);
1106 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1110 break;
1113 /* Get the new top-most structural object class */
1114 objectclass = get_last_structural_class(ac->schema, oc_el_entry,
1115 ac->req);
1116 if (objectclass == NULL) {
1117 ldb_set_errstring(ldb,
1118 "objectclass: cannot delete all structural objectclasses!");
1119 talloc_free(mem_ctx);
1120 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1123 ret = check_unrelated_objectclasses(ac->module, ac->schema,
1124 objectclass,
1125 oc_el_entry);
1126 if (ret != LDB_SUCCESS) {
1127 talloc_free(mem_ctx);
1128 return ret;
1131 /* Now do the sorting */
1132 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1133 oc_el_entry, &sorted);
1134 if (ret != LDB_SUCCESS) {
1135 talloc_free(mem_ctx);
1136 return ret;
1139 /* (Re)-add an empty "objectClass" attribute on the object
1140 * classes change message "msg". */
1141 ldb_msg_remove_attr(msg, "objectClass");
1142 ret = ldb_msg_add_empty(msg, "objectClass",
1143 LDB_FLAG_MOD_REPLACE, &oc_el_entry);
1144 if (ret != LDB_SUCCESS) {
1145 talloc_free(mem_ctx);
1146 return ret;
1149 /* Move from the linked list back into an ldb msg */
1150 for (current = sorted; current; current = current->next) {
1151 const char *objectclass_name = current->objectclass->lDAPDisplayName;
1153 ret = ldb_msg_add_string(msg, "objectClass",
1154 objectclass_name);
1155 if (ret != LDB_SUCCESS) {
1156 ldb_set_errstring(ldb,
1157 "objectclass: could not re-add sorted objectclasses!");
1158 talloc_free(mem_ctx);
1159 return ret;
1164 talloc_free(mem_ctx);
1166 /* Now we have the real and definitive change left to do */
1168 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1169 msg,
1170 ac->req->controls,
1171 ac, oc_op_callback,
1172 ac->req);
1173 LDB_REQ_SET_LOCATION(mod_req);
1174 if (ret != LDB_SUCCESS) {
1175 return ret;
1178 return ldb_next_request(ac->module, mod_req);
1181 static int objectclass_do_rename(struct oc_context *ac);
1183 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1185 static const char * const attrs[] = { "objectClass", NULL };
1186 struct ldb_context *ldb;
1187 struct ldb_request *search_req;
1188 struct oc_context *ac;
1189 struct ldb_dn *parent_dn;
1190 int ret;
1192 ldb = ldb_module_get_ctx(module);
1194 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1196 /* do not manipulate our control entries */
1197 if (ldb_dn_is_special(req->op.rename.olddn)) {
1198 return ldb_next_request(module, req);
1201 ac = oc_init_context(module, req);
1202 if (ac == NULL) {
1203 return ldb_operr(ldb);
1206 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1207 if (parent_dn == NULL) {
1208 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1209 ldb_dn_get_linearized(req->op.rename.olddn));
1210 return LDB_ERR_NO_SUCH_OBJECT;
1213 /* this looks up the parent object for fetching some important
1214 * information (objectclasses, DN normalisation...) */
1215 ret = ldb_build_search_req(&search_req, ldb,
1216 ac, parent_dn, LDB_SCOPE_BASE,
1217 "(objectClass=*)",
1218 attrs, NULL,
1219 ac, get_search_callback,
1220 req);
1221 LDB_REQ_SET_LOCATION(search_req);
1222 if (ret != LDB_SUCCESS) {
1223 return ret;
1226 /* we have to add the show recycled control, as otherwise DRS
1227 deletes will be refused as we will think the target parent
1228 does not exist */
1229 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1230 false, NULL);
1232 if (ret != LDB_SUCCESS) {
1233 return ret;
1236 ac->step_fn = objectclass_do_rename;
1238 return ldb_next_request(ac->module, search_req);
1241 static int objectclass_do_rename2(struct oc_context *ac);
1243 static int objectclass_do_rename(struct oc_context *ac)
1245 static const char * const attrs[] = { "objectClass", NULL };
1246 struct ldb_context *ldb;
1247 struct ldb_request *search_req;
1248 int ret;
1250 ldb = ldb_module_get_ctx(ac->module);
1252 /* Check if we have a valid parent - this check is needed since
1253 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1254 if (ac->search_res == NULL) {
1255 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1256 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1257 return LDB_ERR_OTHER;
1260 /* now assign "search_res2" to the parent entry to have "search_res"
1261 * free for another lookup */
1262 ac->search_res2 = ac->search_res;
1263 ac->search_res = NULL;
1265 /* this looks up the real existing object for fetching some important
1266 * information (objectclasses) */
1267 ret = ldb_build_search_req(&search_req, ldb,
1268 ac, ac->req->op.rename.olddn,
1269 LDB_SCOPE_BASE,
1270 "(objectClass=*)",
1271 attrs, NULL,
1272 ac, get_search_callback,
1273 ac->req);
1274 LDB_REQ_SET_LOCATION(search_req);
1275 if (ret != LDB_SUCCESS) {
1276 return ret;
1279 ac->step_fn = objectclass_do_rename2;
1281 return ldb_next_request(ac->module, search_req);
1284 static int objectclass_do_rename2(struct oc_context *ac)
1286 struct ldb_context *ldb;
1287 struct ldb_request *rename_req;
1288 struct ldb_dn *fixed_dn;
1289 int ret;
1291 ldb = ldb_module_get_ctx(ac->module);
1293 /* Check if we have a valid entry - this check is needed since
1294 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1295 if (ac->search_res == NULL) {
1296 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1297 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1298 return LDB_ERR_NO_SUCH_OBJECT;
1301 if (ac->schema != NULL) {
1302 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1303 const struct dsdb_class *objectclass;
1304 const char *rdn_name;
1305 bool allowed_class = false;
1306 unsigned int i, j;
1307 bool found;
1309 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1310 "objectClass");
1311 if (oc_el_entry == NULL) {
1312 /* existing entry without a valid object class? */
1313 return ldb_operr(ldb);
1315 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1316 if (objectclass == NULL) {
1317 /* existing entry without a valid object class? */
1318 return ldb_operr(ldb);
1321 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1322 if (rdn_name == NULL) {
1323 return ldb_operr(ldb);
1325 found = false;
1326 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1327 const struct dsdb_class *tmp_class =
1328 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1329 &oc_el_entry->values[i]);
1331 if (tmp_class == NULL) continue;
1333 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1334 found = true;
1336 if (!found) {
1337 ldb_asprintf_errstring(ldb,
1338 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1339 rdn_name, objectclass->lDAPDisplayName);
1340 return LDB_ERR_UNWILLING_TO_PERFORM;
1343 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1344 "objectClass");
1345 if (oc_el_parent == NULL) {
1346 /* existing entry without a valid object class? */
1347 return ldb_operr(ldb);
1350 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1351 const struct dsdb_class *sclass;
1353 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1354 &oc_el_parent->values[i]);
1355 if (!sclass) {
1356 /* We don't know this class? what is going on? */
1357 continue;
1359 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1360 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1361 allowed_class = true;
1362 break;
1367 if (!allowed_class) {
1368 ldb_asprintf_errstring(ldb,
1369 "objectclass: structural objectClass %s is not a valid child class for %s",
1370 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1371 return LDB_ERR_NAMING_VIOLATION;
1375 /* Ensure we are not trying to rename it to be a child of itself */
1376 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1377 ac->req->op.rename.newdn) == 0) &&
1378 (ldb_dn_compare(ac->req->op.rename.olddn,
1379 ac->req->op.rename.newdn) != 0)) {
1380 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1381 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1382 return LDB_ERR_UNWILLING_TO_PERFORM;
1385 /* Fix up the DN to be in the standard form, taking
1386 * particular care to match the parent DN */
1387 ret = fix_dn(ldb, ac,
1388 ac->req->op.rename.newdn,
1389 ac->search_res2->message->dn,
1390 &fixed_dn);
1391 if (ret != LDB_SUCCESS) {
1392 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1393 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1394 return ret;
1398 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1399 ac->req->op.rename.olddn, fixed_dn,
1400 ac->req->controls,
1401 ac, oc_op_callback,
1402 ac->req);
1403 LDB_REQ_SET_LOCATION(rename_req);
1404 if (ret != LDB_SUCCESS) {
1405 return ret;
1408 /* perform the rename */
1409 return ldb_next_request(ac->module, rename_req);
1412 static int objectclass_do_delete(struct oc_context *ac);
1414 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1416 static const char * const attrs[] = { "nCName", "objectClass",
1417 "systemFlags",
1418 "isDeleted",
1419 "isCriticalSystemObject", NULL };
1420 struct ldb_context *ldb;
1421 struct ldb_request *search_req;
1422 struct oc_context *ac;
1423 int ret;
1425 ldb = ldb_module_get_ctx(module);
1427 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1429 /* do not manipulate our control entries */
1430 if (ldb_dn_is_special(req->op.del.dn)) {
1431 return ldb_next_request(module, req);
1434 /* Bypass the constraint checks when we do have the "RELAX" control
1435 * set. */
1436 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1437 return ldb_next_request(module, req);
1440 ac = oc_init_context(module, req);
1441 if (ac == NULL) {
1442 return ldb_operr(ldb);
1445 /* this looks up the entry object for fetching some important
1446 * information (object classes, system flags...) */
1447 ret = ldb_build_search_req(&search_req, ldb,
1448 ac, req->op.del.dn, LDB_SCOPE_BASE,
1449 "(objectClass=*)",
1450 attrs, req->controls,
1451 ac, get_search_callback,
1452 req);
1453 LDB_REQ_SET_LOCATION(search_req);
1454 if (ret != LDB_SUCCESS) {
1455 return ret;
1458 ac->step_fn = objectclass_do_delete;
1460 return ldb_next_request(ac->module, search_req);
1463 static int objectclass_do_delete(struct oc_context *ac)
1465 struct ldb_context *ldb;
1466 struct ldb_dn *dn;
1467 int32_t systemFlags;
1468 bool isCriticalSystemObject;
1469 int ret;
1471 ldb = ldb_module_get_ctx(ac->module);
1473 /* Check if we have a valid entry - this check is needed since
1474 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1475 if (ac->search_res == NULL) {
1476 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1477 ldb_dn_get_linearized(ac->req->op.del.dn));
1478 return LDB_ERR_NO_SUCH_OBJECT;
1481 /* DC's ntDSDSA object */
1482 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1483 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1484 ldb_dn_get_linearized(ac->req->op.del.dn));
1485 return LDB_ERR_UNWILLING_TO_PERFORM;
1488 /* DC's rIDSet object */
1489 /* Perform this check only when it does exist - this is needed in order
1490 * to don't let existing provisions break. */
1491 ret = samdb_rid_set_dn(ldb, ac, &dn);
1492 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1493 return ret;
1495 if (ret == LDB_SUCCESS) {
1496 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1497 talloc_free(dn);
1498 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1499 ldb_dn_get_linearized(ac->req->op.del.dn));
1500 return LDB_ERR_UNWILLING_TO_PERFORM;
1502 talloc_free(dn);
1505 /* Only trusted request from system account are allowed to delete
1506 * deleted objects.
1508 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1509 (ldb_req_is_untrusted(ac->req) ||
1510 !dsdb_module_am_system(ac->module))) {
1511 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1512 ldb_dn_get_linearized(ac->req->op.del.dn));
1513 return LDB_ERR_UNWILLING_TO_PERFORM;
1516 /* crossRef objects regarding config, schema and default domain NCs */
1517 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1518 "crossRef") != NULL) {
1519 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1520 "nCName");
1521 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1522 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1523 talloc_free(dn);
1525 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1526 ldb_dn_get_linearized(ac->req->op.del.dn));
1527 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1529 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1530 talloc_free(dn);
1532 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1533 ldb_dn_get_linearized(ac->req->op.del.dn));
1534 return LDB_ERR_UNWILLING_TO_PERFORM;
1536 talloc_free(dn);
1539 /* systemFlags */
1541 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1542 "systemFlags", 0);
1543 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1544 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1545 ldb_dn_get_linearized(ac->req->op.del.dn));
1546 return LDB_ERR_UNWILLING_TO_PERFORM;
1549 /* isCriticalSystemObject - but this only applies on tree delete
1550 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1551 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1552 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1553 "isCriticalSystemObject", false);
1554 if (isCriticalSystemObject) {
1556 * Following the explaination from Microsoft
1557 * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1558 * "I finished the investigation on this behavior.
1559 * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1560 * every object in the tree will be checked to see if it has isCriticalSystemObject
1561 * set to TRUE, including the root node on which the delete operation is performed
1562 * But there is an exception if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1563 * Its deletion is done through SAM manger and isCriticalSystemObject attribute is not checked
1564 * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1565 * which is a SAM object with user class. Therefore the tree deletion is performed without any error
1568 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1569 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1570 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1571 samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1572 ldb_asprintf_errstring(ldb,
1573 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1574 ldb_dn_get_linearized(ac->req->op.del.dn));
1575 return LDB_ERR_UNWILLING_TO_PERFORM;
1580 return ldb_next_request(ac->module, ac->req);
1583 static int objectclass_init(struct ldb_module *module)
1585 struct ldb_context *ldb = ldb_module_get_ctx(module);
1586 int ret;
1588 /* Init everything else */
1589 ret = ldb_next_init(module);
1590 if (ret != LDB_SUCCESS) {
1591 return ret;
1594 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1595 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1597 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1598 if (ret != LDB_SUCCESS) {
1599 ldb_debug(ldb, LDB_DEBUG_ERROR,
1600 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1601 return ldb_operr(ldb);
1604 return ret;
1607 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1608 .name = "objectclass",
1609 .add = objectclass_add,
1610 .modify = objectclass_modify,
1611 .rename = objectclass_rename,
1612 .del = objectclass_delete,
1613 .init_context = objectclass_init
1616 int ldb_objectclass_module_init(const char *version)
1618 LDB_MODULE_CHECK_VERSION(version);
1619 return ldb_register_module(&ldb_objectclass_module_ops);