s3:registry: do not use regdb functions during db upgrade
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blob89dd6efd8a0c79cb8d519078aea62177aca57f02
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, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
105 ldb = ldb_module_get_ctx(module);
107 /* DESIGN:
109 * We work on 4 different 'bins' (implemented here as linked lists):
111 * * sorted: the eventual list, in the order we wish to push
112 * into the database. This is the only ordered list.
114 * * parent_class: The current parent class 'bin' we are
115 * trying to find subclasses for
117 * * subclass: The subclasses we have found so far
119 * * unsorted: The remaining objectClasses
121 * The process is a matter of filtering objectClasses up from
122 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
124 * We start with 'top' (found and promoted to parent_class
125 * initially). Then we find (in unsorted) all the direct
126 * subclasses of 'top'. parent_classes is concatenated onto
127 * the end of 'sorted', and subclass becomes the list in
128 * parent_class.
130 * We then repeat, until we find no more subclasses. Any left
131 * over classes are added to the end.
135 /* Firstly, dump all the objectClass elements into the
136 * unsorted bin, except for 'top', which is special */
137 for (i=0; i < objectclass_element->num_values; i++) {
138 current = talloc(mem_ctx, struct class_list);
139 if (!current) {
140 return ldb_oom(ldb);
142 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
143 if (!current->objectclass) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
145 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146 /* This looks weird, but windows apparently returns this for invalid objectClass values */
147 return LDB_ERR_NO_SUCH_ATTRIBUTE;
148 } else if (current->objectclass->isDefunct) {
149 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
150 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
151 /* This looks weird, but windows apparently returns this for invalid objectClass values */
152 return LDB_ERR_NO_SUCH_ATTRIBUTE;
155 /* Don't add top to list, we will do that later */
156 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
157 DLIST_ADD_END(unsorted, current, struct class_list *);
161 /* Add top here, to prevent duplicates */
162 current = talloc(mem_ctx, struct class_list);
163 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
164 DLIST_ADD_END(sorted, current, struct class_list *);
167 /* For each object: find parent chain */
168 for (current = unsorted; schema && current; current = current->next) {
169 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
170 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
171 break;
174 /* If we didn't get to the end of the list, we need to add this parent */
175 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
176 continue;
179 new_parent = talloc(mem_ctx, struct class_list);
180 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
181 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
186 lowest = UINT_MAX;
187 current_lowest = NULL;
188 for (current = unsorted; schema && current; current = current->next) {
189 if(current->objectclass->subClass_order < lowest) {
190 current_lowest = current;
191 lowest = current->objectclass->subClass_order;
195 if(current_lowest != NULL) {
196 DLIST_REMOVE(unsorted,current_lowest);
197 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
199 } while(unsorted);
202 if (!unsorted) {
203 *sorted_out = sorted;
204 return LDB_SUCCESS;
207 if (!schema) {
208 /* If we don't have schema yet, then just merge the lists again */
209 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
210 *sorted_out = sorted;
211 return LDB_SUCCESS;
214 /* This shouldn't happen, and would break MMC, perhaps there
215 * was no 'top', a conflict in the objectClasses or some other
216 * schema error?
218 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
219 return LDB_ERR_OBJECT_CLASS_VIOLATION;
223 * This checks if we have unrelated object classes in our entry's "objectClass"
224 * attribute. That means "unsatisfied" abstract classes (no concrete subclass)
225 * or two or more disjunct structural ones.
226 * If one of these conditions are true, blame.
228 static int check_unrelated_objectclasses(struct ldb_module *module,
229 const struct dsdb_schema *schema,
230 const struct dsdb_class *struct_objectclass,
231 struct ldb_message_element *objectclass_element)
233 struct ldb_context *ldb = ldb_module_get_ctx(module);
234 unsigned int i;
235 bool found;
237 if (schema == NULL) {
238 return LDB_SUCCESS;
241 for (i = 0; i < objectclass_element->num_values; i++) {
242 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema,
243 &objectclass_element->values[i]);
244 const struct dsdb_class *tmp_class2 = struct_objectclass;
246 /* Pointer comparison can be used due to the same schema str. */
247 if (tmp_class == NULL ||
248 tmp_class == struct_objectclass ||
249 tmp_class->objectClassCategory > 2 ||
250 ldb_attr_cmp(tmp_class->lDAPDisplayName, "top") == 0) {
251 continue;
254 found = false;
255 while (!found &&
256 ldb_attr_cmp(tmp_class2->lDAPDisplayName, "top") != 0) {
257 tmp_class2 = dsdb_class_by_lDAPDisplayName(schema,
258 tmp_class2->subClassOf);
259 if (tmp_class2 == tmp_class) {
260 found = true;
263 if (found) {
264 continue;
267 ldb_asprintf_errstring(ldb,
268 "objectclass: the objectclass '%s' seems to be unrelated to the entry!",
269 tmp_class->lDAPDisplayName);
270 return LDB_ERR_OBJECT_CLASS_VIOLATION;
273 return LDB_SUCCESS;
276 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
278 struct ldb_context *ldb;
279 struct oc_context *ac;
280 int ret;
282 ac = talloc_get_type(req->context, struct oc_context);
283 ldb = ldb_module_get_ctx(ac->module);
285 if (!ares) {
286 return ldb_module_done(ac->req, NULL, NULL,
287 LDB_ERR_OPERATIONS_ERROR);
289 if (ares->error != LDB_SUCCESS &&
290 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
291 return ldb_module_done(ac->req, ares->controls,
292 ares->response, ares->error);
295 ldb_reset_err_string(ldb);
297 switch (ares->type) {
298 case LDB_REPLY_ENTRY:
299 if (ac->search_res != NULL) {
300 ldb_set_errstring(ldb, "Too many results");
301 talloc_free(ares);
302 return ldb_module_done(ac->req, NULL, NULL,
303 LDB_ERR_OPERATIONS_ERROR);
306 ac->search_res = talloc_steal(ac, ares);
307 break;
309 case LDB_REPLY_REFERRAL:
310 /* ignore */
311 talloc_free(ares);
312 break;
314 case LDB_REPLY_DONE:
315 talloc_free(ares);
316 ret = ac->step_fn(ac);
317 if (ret != LDB_SUCCESS) {
318 return ldb_module_done(ac->req, NULL, NULL, ret);
320 break;
323 return LDB_SUCCESS;
326 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
328 struct oc_context *ac;
330 ac = talloc_get_type(req->context, struct oc_context);
332 if (!ares) {
333 return ldb_module_done(ac->req, NULL, NULL,
334 LDB_ERR_OPERATIONS_ERROR);
337 if (ares->type == LDB_REPLY_REFERRAL) {
338 return ldb_module_send_referral(ac->req, ares->referral);
341 if (ares->error != LDB_SUCCESS) {
342 return ldb_module_done(ac->req, ares->controls,
343 ares->response, ares->error);
346 if (ares->type != LDB_REPLY_DONE) {
347 talloc_free(ares);
348 return ldb_module_done(ac->req, NULL, NULL,
349 LDB_ERR_OPERATIONS_ERROR);
352 return ldb_module_done(ac->req, ares->controls,
353 ares->response, ares->error);
356 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
358 This should mean that if the parent is:
359 CN=Users,DC=samba,DC=example,DC=com
360 and a proposed child is
361 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
363 The resulting DN should be:
365 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
368 static int fix_dn(struct ldb_context *ldb,
369 TALLOC_CTX *mem_ctx,
370 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
371 struct ldb_dn **fixed_dn)
373 char *upper_rdn_attr;
374 const struct ldb_val *rdn_val;
376 /* Fix up the DN to be in the standard form, taking particular care to
377 * match the parent DN */
378 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
379 if (*fixed_dn == NULL) {
380 return ldb_oom(ldb);
383 /* We need the attribute name in upper case */
384 upper_rdn_attr = strupper_talloc(*fixed_dn,
385 ldb_dn_get_rdn_name(newdn));
386 if (upper_rdn_attr == NULL) {
387 return ldb_oom(ldb);
390 /* Create a new child */
391 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
392 return ldb_operr(ldb);
395 rdn_val = ldb_dn_get_rdn_val(newdn);
396 if (rdn_val == NULL) {
397 return ldb_operr(ldb);
400 #if 0
401 /* the rules for rDN length constraints are more complex than
402 this. Until we understand them we need to leave this
403 constraint out. Otherwise we break replication, as windows
404 does sometimes send us rDNs longer than 64 */
405 if (!rdn_val || rdn_val->length > 64) {
406 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
408 #endif
411 /* And replace it with CN=foo (we need the attribute in upper case) */
412 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
416 static int objectclass_do_add(struct oc_context *ac);
418 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
420 struct ldb_context *ldb;
421 struct ldb_request *search_req;
422 struct oc_context *ac;
423 struct ldb_dn *parent_dn;
424 const struct ldb_val *val;
425 int ret;
426 static const char * const parent_attrs[] = { "objectClass", NULL };
428 ldb = ldb_module_get_ctx(module);
430 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
432 /* do not manipulate our control entries */
433 if (ldb_dn_is_special(req->op.add.message->dn)) {
434 return ldb_next_request(module, req);
437 /* An add operation on the basedn without "NC-add" operation isn't
438 * allowed. */
439 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
440 unsigned int instanceType;
442 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
443 "instanceType", 0);
444 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
445 char *referral_uri;
446 /* When we are trying to readd the root basedn then
447 * this is denied, but with an interesting mechanism:
448 * there is generated a referral with the last
449 * component value as hostname. */
450 val = ldb_dn_get_component_val(req->op.add.message->dn,
451 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
452 if (val == NULL) {
453 return ldb_operr(ldb);
455 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
456 ldb_dn_get_linearized(req->op.add.message->dn));
457 if (referral_uri == NULL) {
458 return ldb_module_oom(module);
461 return ldb_module_send_referral(req, referral_uri);
465 ac = oc_init_context(module, req);
466 if (ac == NULL) {
467 return ldb_operr(ldb);
470 /* If there isn't a parent, just go on to the add processing */
471 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
472 return objectclass_do_add(ac);
475 /* get copy of parent DN */
476 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
477 if (parent_dn == NULL) {
478 return ldb_operr(ldb);
481 ret = ldb_build_search_req(&search_req, ldb,
482 ac, parent_dn, LDB_SCOPE_BASE,
483 "(objectClass=*)", parent_attrs,
484 NULL,
485 ac, get_search_callback,
486 req);
487 LDB_REQ_SET_LOCATION(search_req);
488 if (ret != LDB_SUCCESS) {
489 return ret;
492 ac->step_fn = objectclass_do_add;
494 return ldb_next_request(ac->module, search_req);
499 check if this is a special RODC nTDSDSA add
501 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
502 const struct dsdb_class *objectclass)
504 struct ldb_control *rodc_control;
506 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
507 return false;
509 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
510 if (!rodc_control) {
511 return false;
514 rodc_control->critical = false;
515 return true;
518 static int objectclass_do_add(struct oc_context *ac)
520 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
521 struct ldb_request *add_req;
522 struct ldb_message_element *objectclass_element, *el;
523 struct ldb_message *msg;
524 TALLOC_CTX *mem_ctx;
525 struct class_list *sorted, *current;
526 const char *rdn_name = NULL;
527 char *value;
528 const struct dsdb_class *objectclass;
529 struct ldb_dn *objectcategory;
530 int32_t systemFlags = 0;
531 unsigned int i, j;
532 bool found;
533 int ret;
535 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
536 if (msg == NULL) {
537 return ldb_module_oom(ac->module);
540 /* Check if we have a valid parent - this check is needed since
541 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
542 if (ac->search_res == NULL) {
543 unsigned int instanceType;
545 /* An add operation on partition DNs without "NC-add" operation
546 * isn't allowed. */
547 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
549 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
550 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
551 ldb_dn_get_linearized(msg->dn));
552 return LDB_ERR_NO_SUCH_OBJECT;
555 /* Don't keep any error messages - we've to add a partition */
556 ldb_set_errstring(ldb, NULL);
557 } else {
558 /* Fix up the DN to be in the standard form, taking
559 * particular care to match the parent DN */
560 ret = fix_dn(ldb, msg,
561 ac->req->op.add.message->dn,
562 ac->search_res->message->dn,
563 &msg->dn);
564 if (ret != LDB_SUCCESS) {
565 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
566 ldb_dn_get_linearized(ac->req->op.add.message->dn));
567 return ret;
571 if (ac->schema != NULL) {
572 objectclass_element = ldb_msg_find_element(msg, "objectClass");
573 if (!objectclass_element) {
574 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
575 ldb_dn_get_linearized(msg->dn));
576 return LDB_ERR_OBJECT_CLASS_VIOLATION;
578 if (objectclass_element->num_values == 0) {
579 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
580 ldb_dn_get_linearized(msg->dn));
581 return LDB_ERR_CONSTRAINT_VIOLATION;
584 mem_ctx = talloc_new(ac);
585 if (mem_ctx == NULL) {
586 return ldb_module_oom(ac->module);
589 /* Here we do now get the "objectClass" list from the
590 * database. */
591 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
592 objectclass_element, &sorted);
593 if (ret != LDB_SUCCESS) {
594 talloc_free(mem_ctx);
595 return ret;
598 ldb_msg_remove_element(msg, objectclass_element);
600 /* Well, now we shouldn't find any additional "objectClass"
601 * message element (required by the AD specification). */
602 objectclass_element = ldb_msg_find_element(msg, "objectClass");
603 if (objectclass_element != NULL) {
604 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
605 ldb_dn_get_linearized(msg->dn));
606 talloc_free(mem_ctx);
607 return LDB_ERR_OBJECT_CLASS_VIOLATION;
610 /* We must completely replace the existing objectClass entry,
611 * because we need it sorted. */
612 ret = ldb_msg_add_empty(msg, "objectClass", 0,
613 &objectclass_element);
614 if (ret != LDB_SUCCESS) {
615 talloc_free(mem_ctx);
616 return ret;
619 /* Move from the linked list back into an ldb msg */
620 for (current = sorted; current; current = current->next) {
621 const char *objectclass_name = current->objectclass->lDAPDisplayName;
623 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
624 if (ret != LDB_SUCCESS) {
625 ldb_set_errstring(ldb,
626 "objectclass: could not re-add sorted "
627 "objectclass to modify msg");
628 talloc_free(mem_ctx);
629 return ret;
633 talloc_free(mem_ctx);
635 /* Make sure its valid to add an object of this type */
636 objectclass = get_last_structural_class(ac->schema,
637 objectclass_element, ac->req);
638 if(objectclass == NULL) {
639 ldb_asprintf_errstring(ldb,
640 "Failed to find a structural class for %s",
641 ldb_dn_get_linearized(msg->dn));
642 return LDB_ERR_UNWILLING_TO_PERFORM;
645 ret = check_unrelated_objectclasses(ac->module, ac->schema,
646 objectclass,
647 objectclass_element);
648 if (ret != LDB_SUCCESS) {
649 return ret;
652 rdn_name = ldb_dn_get_rdn_name(msg->dn);
653 if (rdn_name == NULL) {
654 return ldb_operr(ldb);
656 found = false;
657 for (i = 0; (!found) && (i < objectclass_element->num_values);
658 i++) {
659 const struct dsdb_class *tmp_class =
660 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
661 &objectclass_element->values[i]);
663 if (tmp_class == NULL) continue;
665 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
666 found = true;
668 if (!found) {
669 ldb_asprintf_errstring(ldb,
670 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
671 rdn_name, objectclass->lDAPDisplayName);
672 return LDB_ERR_NAMING_VIOLATION;
675 if (objectclass->systemOnly &&
676 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
677 !check_rodc_ntdsdsa_add(ac, objectclass)) {
678 ldb_asprintf_errstring(ldb,
679 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
680 objectclass->lDAPDisplayName,
681 ldb_dn_get_linearized(msg->dn));
682 return LDB_ERR_UNWILLING_TO_PERFORM;
685 if (ac->search_res && ac->search_res->message) {
686 struct ldb_message_element *oc_el
687 = ldb_msg_find_element(ac->search_res->message, "objectClass");
689 bool allowed_class = false;
690 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
691 const struct dsdb_class *sclass;
693 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
694 &oc_el->values[i]);
695 if (!sclass) {
696 /* We don't know this class? what is going on? */
697 continue;
699 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
700 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
701 allowed_class = true;
702 break;
707 if (!allowed_class) {
708 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
709 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
710 return LDB_ERR_NAMING_VIOLATION;
714 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
715 "objectCategory");
716 if (objectcategory == NULL) {
717 struct dsdb_extended_dn_store_format *dn_format =
718 talloc_get_type(ldb_module_get_private(ac->module),
719 struct dsdb_extended_dn_store_format);
720 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
721 /* Strip off extended components */
722 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
723 objectclass->defaultObjectCategory);
724 value = ldb_dn_alloc_linearized(msg, dn);
725 talloc_free(dn);
726 } else {
727 value = talloc_strdup(msg,
728 objectclass->defaultObjectCategory);
730 if (value == NULL) {
731 return ldb_module_oom(ac->module);
734 ret = ldb_msg_add_string(msg, "objectCategory", value);
735 if (ret != LDB_SUCCESS) {
736 return ret;
738 } else {
739 const struct dsdb_class *ocClass =
740 dsdb_class_by_cn_ldb_val(ac->schema,
741 ldb_dn_get_rdn_val(objectcategory));
742 if (ocClass != NULL) {
743 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
744 ocClass->defaultObjectCategory);
745 if (ldb_dn_compare(objectcategory, dn) != 0) {
746 ocClass = NULL;
749 talloc_free(objectcategory);
750 if (ocClass == NULL) {
751 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
752 ldb_dn_get_linearized(msg->dn));
753 return LDB_ERR_OBJECT_CLASS_VIOLATION;
757 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
758 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
759 "TRUE");
762 /* There are very special rules for systemFlags, see MS-ADTS
763 * MS-ADTS 3.1.1.5.2.4 */
765 el = ldb_msg_find_element(msg, "systemFlags");
766 if ((el != NULL) && (el->num_values > 1)) {
767 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
768 ldb_dn_get_linearized(msg->dn));
769 return LDB_ERR_CONSTRAINT_VIOLATION;
772 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
774 ldb_msg_remove_attr(msg, "systemFlags");
776 /* Only the following flags may be set by a client */
777 if (ldb_request_get_control(ac->req,
778 LDB_CONTROL_RELAX_OID) == NULL) {
779 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
780 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
781 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
782 | SYSTEM_FLAG_ATTR_IS_RDN );
785 /* But the last one ("ATTR_IS_RDN") is only allowed on
786 * "attributeSchema" objects. So truncate if it does not fit. */
787 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
788 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
791 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
792 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
793 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
794 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
795 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
796 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
797 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
798 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
799 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
800 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
801 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
802 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
803 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
805 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
807 if (el || systemFlags != 0) {
808 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
809 systemFlags);
810 if (ret != LDB_SUCCESS) {
811 return ret;
815 /* make sure that "isCriticalSystemObject" is not specified! */
816 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
817 if ((el != NULL) &&
818 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
819 ldb_set_errstring(ldb,
820 "objectclass: 'isCriticalSystemObject' must not be specified!");
821 return LDB_ERR_UNWILLING_TO_PERFORM;
825 ret = ldb_build_add_req(&add_req, ldb, ac,
826 msg,
827 ac->req->controls,
828 ac, oc_op_callback,
829 ac->req);
830 LDB_REQ_SET_LOCATION(add_req);
831 if (ret != LDB_SUCCESS) {
832 return ret;
835 /* perform the add */
836 return ldb_next_request(ac->module, add_req);
839 static int oc_modify_callback(struct ldb_request *req,
840 struct ldb_reply *ares);
841 static int objectclass_do_mod(struct oc_context *ac);
843 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
845 struct ldb_context *ldb = ldb_module_get_ctx(module);
846 struct ldb_message_element *objectclass_element;
847 struct ldb_message *msg;
848 struct ldb_request *down_req;
849 struct oc_context *ac;
850 bool oc_changes = false;
851 int ret;
853 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
855 /* do not manipulate our control entries */
856 if (ldb_dn_is_special(req->op.mod.message->dn)) {
857 return ldb_next_request(module, req);
860 /* As with the "real" AD we don't accept empty messages */
861 if (req->op.mod.message->num_elements == 0) {
862 ldb_set_errstring(ldb, "objectclass: modify message must have "
863 "elements/attributes!");
864 return LDB_ERR_UNWILLING_TO_PERFORM;
867 ac = oc_init_context(module, req);
868 if (ac == NULL) {
869 return ldb_operr(ldb);
872 /* Without schema, there isn't much to do here */
873 if (ac->schema == NULL) {
874 talloc_free(ac);
875 return ldb_next_request(module, req);
878 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
879 if (msg == NULL) {
880 return ldb_module_oom(ac->module);
883 /* For now change everything except the objectclasses */
885 objectclass_element = ldb_msg_find_element(msg, "objectClass");
886 if (objectclass_element != NULL) {
887 ldb_msg_remove_attr(msg, "objectClass");
888 oc_changes = true;
891 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
892 * only on application NCs - not on the default ones */
893 if (oc_changes &&
894 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
895 struct ldb_dn *nc_root;
897 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
898 &nc_root);
899 if (ret != LDB_SUCCESS) {
900 return ret;
903 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
904 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
905 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
906 ldb_set_errstring(ldb,
907 "objectclass: object class changes on objects under the standard name contexts not allowed!");
908 return LDB_ERR_UNWILLING_TO_PERFORM;
911 talloc_free(nc_root);
914 ret = ldb_build_mod_req(&down_req, ldb, ac,
915 msg,
916 req->controls, ac,
917 oc_changes ? oc_modify_callback : oc_op_callback,
918 req);
919 LDB_REQ_SET_LOCATION(down_req);
920 if (ret != LDB_SUCCESS) {
921 return ret;
924 return ldb_next_request(module, down_req);
927 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
929 static const char * const attrs[] = { "objectClass", NULL };
930 struct ldb_context *ldb;
931 struct ldb_request *search_req;
932 struct oc_context *ac;
933 int ret;
935 ac = talloc_get_type(req->context, struct oc_context);
936 ldb = ldb_module_get_ctx(ac->module);
938 if (!ares) {
939 return ldb_module_done(ac->req, NULL, NULL,
940 LDB_ERR_OPERATIONS_ERROR);
943 if (ares->type == LDB_REPLY_REFERRAL) {
944 return ldb_module_send_referral(ac->req, ares->referral);
947 if (ares->error != LDB_SUCCESS) {
948 return ldb_module_done(ac->req, ares->controls,
949 ares->response, ares->error);
952 if (ares->type != LDB_REPLY_DONE) {
953 talloc_free(ares);
954 return ldb_module_done(ac->req, NULL, NULL,
955 LDB_ERR_OPERATIONS_ERROR);
958 talloc_free(ares);
960 /* this looks up the real existing object for fetching some important
961 * information (objectclasses) */
962 ret = ldb_build_search_req(&search_req, ldb,
963 ac, ac->req->op.mod.message->dn,
964 LDB_SCOPE_BASE,
965 "(objectClass=*)",
966 attrs, NULL,
967 ac, get_search_callback,
968 ac->req);
969 LDB_REQ_SET_LOCATION(search_req);
970 if (ret != LDB_SUCCESS) {
971 return ldb_module_done(ac->req, NULL, NULL, ret);
974 ac->step_fn = objectclass_do_mod;
976 ret = ldb_next_request(ac->module, search_req);
977 if (ret != LDB_SUCCESS) {
978 return ldb_module_done(ac->req, NULL, NULL, ret);
981 return LDB_SUCCESS;
984 static int objectclass_do_mod(struct oc_context *ac)
986 struct ldb_context *ldb;
987 struct ldb_request *mod_req;
988 struct ldb_message_element *oc_el_entry, *oc_el_change;
989 struct ldb_val *vals;
990 struct ldb_message *msg;
991 TALLOC_CTX *mem_ctx;
992 struct class_list *sorted, *current;
993 const struct dsdb_class *objectclass;
994 unsigned int i, j, k;
995 bool found;
996 int ret;
998 ldb = ldb_module_get_ctx(ac->module);
1000 /* we should always have a valid entry when we enter here */
1001 if (ac->search_res == NULL) {
1002 return ldb_operr(ldb);
1005 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1006 "objectClass");
1007 if (oc_el_entry == NULL) {
1008 /* existing entry without a valid object class? */
1009 return ldb_operr(ldb);
1012 /* use a new message structure */
1013 msg = ldb_msg_new(ac);
1014 if (msg == NULL) {
1015 return ldb_module_oom(ac->module);
1018 msg->dn = ac->req->op.mod.message->dn;
1020 mem_ctx = talloc_new(ac);
1021 if (mem_ctx == NULL) {
1022 return ldb_module_oom(ac->module);
1025 /* We've to walk over all "objectClass" message elements */
1026 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
1027 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
1028 "objectClass") != 0) {
1029 continue;
1032 oc_el_change = &ac->req->op.mod.message->elements[k];
1034 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
1035 case LDB_FLAG_MOD_ADD:
1036 /* Merge the two message elements */
1037 for (i = 0; i < oc_el_change->num_values; i++) {
1038 for (j = 0; j < oc_el_entry->num_values; j++) {
1039 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1040 (char *)oc_el_entry->values[j].data) == 0) {
1041 ldb_asprintf_errstring(ldb,
1042 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
1043 (int)oc_el_change->values[i].length,
1044 (const char *)oc_el_change->values[i].data);
1045 talloc_free(mem_ctx);
1046 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1049 /* append the new object class value - code was
1050 * copied from "ldb_msg_add_value" */
1051 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
1052 struct ldb_val,
1053 oc_el_entry->num_values + 1);
1054 if (vals == NULL) {
1055 talloc_free(mem_ctx);
1056 return ldb_module_oom(ac->module);
1058 oc_el_entry->values = vals;
1059 oc_el_entry->values[oc_el_entry->num_values] =
1060 oc_el_change->values[i];
1061 ++(oc_el_entry->num_values);
1064 break;
1066 case LDB_FLAG_MOD_REPLACE:
1068 * In this case the new "oc_el_entry" is simply
1069 * "oc_el_change"
1071 oc_el_entry = oc_el_change;
1073 break;
1075 case LDB_FLAG_MOD_DELETE:
1076 /* Merge the two message elements */
1077 for (i = 0; i < oc_el_change->num_values; i++) {
1078 found = false;
1079 for (j = 0; j < oc_el_entry->num_values; j++) {
1080 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1081 (char *)oc_el_entry->values[j].data) == 0) {
1082 found = true;
1083 /* delete the object class value
1084 * - code was copied from
1085 * "ldb_msg_remove_element" */
1086 if (j != oc_el_entry->num_values - 1) {
1087 memmove(&oc_el_entry->values[j],
1088 &oc_el_entry->values[j+1],
1089 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1091 --(oc_el_entry->num_values);
1092 break;
1095 if (!found) {
1096 /* we cannot delete a not existing
1097 * object class */
1098 ldb_asprintf_errstring(ldb,
1099 "objectclass: cannot delete this objectclass: '%.*s'!",
1100 (int)oc_el_change->values[i].length,
1101 (const char *)oc_el_change->values[i].data);
1102 talloc_free(mem_ctx);
1103 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1107 break;
1110 /* Get the new top-most structural object class */
1111 objectclass = get_last_structural_class(ac->schema, oc_el_entry,
1112 ac->req);
1113 if (objectclass == NULL) {
1114 ldb_set_errstring(ldb,
1115 "objectclass: cannot delete all structural objectclasses!");
1116 talloc_free(mem_ctx);
1117 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1120 ret = check_unrelated_objectclasses(ac->module, ac->schema,
1121 objectclass,
1122 oc_el_entry);
1123 if (ret != LDB_SUCCESS) {
1124 talloc_free(mem_ctx);
1125 return ret;
1128 /* Now do the sorting */
1129 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1130 oc_el_entry, &sorted);
1131 if (ret != LDB_SUCCESS) {
1132 talloc_free(mem_ctx);
1133 return ret;
1136 /* (Re)-add an empty "objectClass" attribute on the object
1137 * classes change message "msg". */
1138 ldb_msg_remove_attr(msg, "objectClass");
1139 ret = ldb_msg_add_empty(msg, "objectClass",
1140 LDB_FLAG_MOD_REPLACE, &oc_el_entry);
1141 if (ret != LDB_SUCCESS) {
1142 talloc_free(mem_ctx);
1143 return ret;
1146 /* Move from the linked list back into an ldb msg */
1147 for (current = sorted; current; current = current->next) {
1148 const char *objectclass_name = current->objectclass->lDAPDisplayName;
1150 ret = ldb_msg_add_string(msg, "objectClass",
1151 objectclass_name);
1152 if (ret != LDB_SUCCESS) {
1153 ldb_set_errstring(ldb,
1154 "objectclass: could not re-add sorted objectclasses!");
1155 talloc_free(mem_ctx);
1156 return ret;
1161 talloc_free(mem_ctx);
1163 /* Now we have the real and definitive change left to do */
1165 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1166 msg,
1167 ac->req->controls,
1168 ac, oc_op_callback,
1169 ac->req);
1170 LDB_REQ_SET_LOCATION(mod_req);
1171 if (ret != LDB_SUCCESS) {
1172 return ret;
1175 return ldb_next_request(ac->module, mod_req);
1178 static int objectclass_do_rename(struct oc_context *ac);
1180 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1182 static const char * const attrs[] = { "objectClass", NULL };
1183 struct ldb_context *ldb;
1184 struct ldb_request *search_req;
1185 struct oc_context *ac;
1186 struct ldb_dn *parent_dn;
1187 int ret;
1189 ldb = ldb_module_get_ctx(module);
1191 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1193 /* do not manipulate our control entries */
1194 if (ldb_dn_is_special(req->op.rename.olddn)) {
1195 return ldb_next_request(module, req);
1198 ac = oc_init_context(module, req);
1199 if (ac == NULL) {
1200 return ldb_operr(ldb);
1203 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1204 if (parent_dn == NULL) {
1205 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1206 ldb_dn_get_linearized(req->op.rename.olddn));
1207 return LDB_ERR_NO_SUCH_OBJECT;
1210 /* this looks up the parent object for fetching some important
1211 * information (objectclasses, DN normalisation...) */
1212 ret = ldb_build_search_req(&search_req, ldb,
1213 ac, parent_dn, LDB_SCOPE_BASE,
1214 "(objectClass=*)",
1215 attrs, NULL,
1216 ac, get_search_callback,
1217 req);
1218 LDB_REQ_SET_LOCATION(search_req);
1219 if (ret != LDB_SUCCESS) {
1220 return ret;
1223 /* we have to add the show recycled control, as otherwise DRS
1224 deletes will be refused as we will think the target parent
1225 does not exist */
1226 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1227 false, NULL);
1229 if (ret != LDB_SUCCESS) {
1230 return ret;
1233 ac->step_fn = objectclass_do_rename;
1235 return ldb_next_request(ac->module, search_req);
1238 static int objectclass_do_rename2(struct oc_context *ac);
1240 static int objectclass_do_rename(struct oc_context *ac)
1242 static const char * const attrs[] = { "objectClass", NULL };
1243 struct ldb_context *ldb;
1244 struct ldb_request *search_req;
1245 int ret;
1247 ldb = ldb_module_get_ctx(ac->module);
1249 /* Check if we have a valid parent - this check is needed since
1250 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1251 if (ac->search_res == NULL) {
1252 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1253 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1254 return LDB_ERR_OTHER;
1257 /* now assign "search_res2" to the parent entry to have "search_res"
1258 * free for another lookup */
1259 ac->search_res2 = ac->search_res;
1260 ac->search_res = NULL;
1262 /* this looks up the real existing object for fetching some important
1263 * information (objectclasses) */
1264 ret = ldb_build_search_req(&search_req, ldb,
1265 ac, ac->req->op.rename.olddn,
1266 LDB_SCOPE_BASE,
1267 "(objectClass=*)",
1268 attrs, NULL,
1269 ac, get_search_callback,
1270 ac->req);
1271 LDB_REQ_SET_LOCATION(search_req);
1272 if (ret != LDB_SUCCESS) {
1273 return ret;
1276 ac->step_fn = objectclass_do_rename2;
1278 return ldb_next_request(ac->module, search_req);
1281 static int objectclass_do_rename2(struct oc_context *ac)
1283 struct ldb_context *ldb;
1284 struct ldb_request *rename_req;
1285 struct ldb_dn *fixed_dn;
1286 int ret;
1288 ldb = ldb_module_get_ctx(ac->module);
1290 /* Check if we have a valid entry - this check is needed since
1291 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1292 if (ac->search_res == NULL) {
1293 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1294 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1295 return LDB_ERR_NO_SUCH_OBJECT;
1298 if (ac->schema != NULL) {
1299 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1300 const struct dsdb_class *objectclass;
1301 const char *rdn_name;
1302 bool allowed_class = false;
1303 unsigned int i, j;
1304 bool found;
1306 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1307 "objectClass");
1308 if (oc_el_entry == NULL) {
1309 /* existing entry without a valid object class? */
1310 return ldb_operr(ldb);
1312 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1313 if (objectclass == NULL) {
1314 /* existing entry without a valid object class? */
1315 return ldb_operr(ldb);
1318 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1319 if (rdn_name == NULL) {
1320 return ldb_operr(ldb);
1322 found = false;
1323 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1324 const struct dsdb_class *tmp_class =
1325 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1326 &oc_el_entry->values[i]);
1328 if (tmp_class == NULL) continue;
1330 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1331 found = true;
1333 if (!found) {
1334 ldb_asprintf_errstring(ldb,
1335 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1336 rdn_name, objectclass->lDAPDisplayName);
1337 return LDB_ERR_UNWILLING_TO_PERFORM;
1340 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1341 "objectClass");
1342 if (oc_el_parent == NULL) {
1343 /* existing entry without a valid object class? */
1344 return ldb_operr(ldb);
1347 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1348 const struct dsdb_class *sclass;
1350 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1351 &oc_el_parent->values[i]);
1352 if (!sclass) {
1353 /* We don't know this class? what is going on? */
1354 continue;
1356 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1357 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1358 allowed_class = true;
1359 break;
1364 if (!allowed_class) {
1365 ldb_asprintf_errstring(ldb,
1366 "objectclass: structural objectClass %s is not a valid child class for %s",
1367 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1368 return LDB_ERR_NAMING_VIOLATION;
1372 /* Ensure we are not trying to rename it to be a child of itself */
1373 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1374 ac->req->op.rename.newdn) == 0) &&
1375 (ldb_dn_compare(ac->req->op.rename.olddn,
1376 ac->req->op.rename.newdn) != 0)) {
1377 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1378 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1379 return LDB_ERR_UNWILLING_TO_PERFORM;
1382 /* Fix up the DN to be in the standard form, taking
1383 * particular care to match the parent DN */
1384 ret = fix_dn(ldb, ac,
1385 ac->req->op.rename.newdn,
1386 ac->search_res2->message->dn,
1387 &fixed_dn);
1388 if (ret != LDB_SUCCESS) {
1389 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1390 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1391 return ret;
1395 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1396 ac->req->op.rename.olddn, fixed_dn,
1397 ac->req->controls,
1398 ac, oc_op_callback,
1399 ac->req);
1400 LDB_REQ_SET_LOCATION(rename_req);
1401 if (ret != LDB_SUCCESS) {
1402 return ret;
1405 /* perform the rename */
1406 return ldb_next_request(ac->module, rename_req);
1409 static int objectclass_do_delete(struct oc_context *ac);
1411 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1413 static const char * const attrs[] = { "nCName", "objectClass",
1414 "systemFlags",
1415 "isDeleted",
1416 "isCriticalSystemObject", NULL };
1417 struct ldb_context *ldb;
1418 struct ldb_request *search_req;
1419 struct oc_context *ac;
1420 int ret;
1422 ldb = ldb_module_get_ctx(module);
1424 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1426 /* do not manipulate our control entries */
1427 if (ldb_dn_is_special(req->op.del.dn)) {
1428 return ldb_next_request(module, req);
1431 /* Bypass the constraint checks when we do have the "RELAX" control
1432 * set. */
1433 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1434 return ldb_next_request(module, req);
1437 ac = oc_init_context(module, req);
1438 if (ac == NULL) {
1439 return ldb_operr(ldb);
1442 /* this looks up the entry object for fetching some important
1443 * information (object classes, system flags...) */
1444 ret = ldb_build_search_req(&search_req, ldb,
1445 ac, req->op.del.dn, LDB_SCOPE_BASE,
1446 "(objectClass=*)",
1447 attrs, req->controls,
1448 ac, get_search_callback,
1449 req);
1450 LDB_REQ_SET_LOCATION(search_req);
1451 if (ret != LDB_SUCCESS) {
1452 return ret;
1455 ac->step_fn = objectclass_do_delete;
1457 return ldb_next_request(ac->module, search_req);
1460 static int objectclass_do_delete(struct oc_context *ac)
1462 struct ldb_context *ldb;
1463 struct ldb_dn *dn;
1464 int32_t systemFlags;
1465 bool isCriticalSystemObject;
1466 int ret;
1468 ldb = ldb_module_get_ctx(ac->module);
1470 /* Check if we have a valid entry - this check is needed since
1471 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1472 if (ac->search_res == NULL) {
1473 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1474 ldb_dn_get_linearized(ac->req->op.del.dn));
1475 return LDB_ERR_NO_SUCH_OBJECT;
1478 /* DC's ntDSDSA object */
1479 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1480 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1481 ldb_dn_get_linearized(ac->req->op.del.dn));
1482 return LDB_ERR_UNWILLING_TO_PERFORM;
1485 /* DC's rIDSet object */
1486 /* Perform this check only when it does exist - this is needed in order
1487 * to don't let existing provisions break. */
1488 ret = samdb_rid_set_dn(ldb, ac, &dn);
1489 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1490 return ret;
1492 if (ret == LDB_SUCCESS) {
1493 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1494 talloc_free(dn);
1495 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1496 ldb_dn_get_linearized(ac->req->op.del.dn));
1497 return LDB_ERR_UNWILLING_TO_PERFORM;
1499 talloc_free(dn);
1502 /* Only trusted request from system account are allowed to delete
1503 * deleted objects.
1505 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1506 (ldb_req_is_untrusted(ac->req) ||
1507 !dsdb_module_am_system(ac->module))) {
1508 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1509 ldb_dn_get_linearized(ac->req->op.del.dn));
1510 return LDB_ERR_UNWILLING_TO_PERFORM;
1513 /* crossRef objects regarding config, schema and default domain NCs */
1514 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1515 "crossRef") != NULL) {
1516 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1517 "nCName");
1518 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1519 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1520 talloc_free(dn);
1522 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1523 ldb_dn_get_linearized(ac->req->op.del.dn));
1524 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1526 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1527 talloc_free(dn);
1529 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1530 ldb_dn_get_linearized(ac->req->op.del.dn));
1531 return LDB_ERR_UNWILLING_TO_PERFORM;
1533 talloc_free(dn);
1536 /* systemFlags */
1538 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1539 "systemFlags", 0);
1540 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1541 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1542 ldb_dn_get_linearized(ac->req->op.del.dn));
1543 return LDB_ERR_UNWILLING_TO_PERFORM;
1546 /* isCriticalSystemObject - but this only applies on tree delete
1547 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1548 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1549 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1550 "isCriticalSystemObject", false);
1551 if (isCriticalSystemObject) {
1552 ldb_asprintf_errstring(ldb,
1553 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1554 ldb_dn_get_linearized(ac->req->op.del.dn));
1555 return LDB_ERR_UNWILLING_TO_PERFORM;
1559 return ldb_next_request(ac->module, ac->req);
1562 static int objectclass_init(struct ldb_module *module)
1564 struct ldb_context *ldb = ldb_module_get_ctx(module);
1565 int ret;
1567 /* Init everything else */
1568 ret = ldb_next_init(module);
1569 if (ret != LDB_SUCCESS) {
1570 return ret;
1573 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1574 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1576 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1577 if (ret != LDB_SUCCESS) {
1578 ldb_debug(ldb, LDB_DEBUG_ERROR,
1579 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1580 return ldb_operr(ldb);
1583 return ret;
1586 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1587 .name = "objectclass",
1588 .add = objectclass_add,
1589 .modify = objectclass_modify,
1590 .rename = objectclass_rename,
1591 .del = objectclass_delete,
1592 .init_context = objectclass_init
1595 int ldb_objectclass_module_init(const char *version)
1597 LDB_MODULE_CHECK_VERSION(version);
1598 return ldb_register_module(&ldb_objectclass_module_ops);