s4:objectclass LDB module - "objectclass_add" - small optimisation
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blob6e087b989708b3b9272fe0b44073339cc69417cc
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;
222 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
224 struct ldb_context *ldb;
225 struct oc_context *ac;
226 int ret;
228 ac = talloc_get_type(req->context, struct oc_context);
229 ldb = ldb_module_get_ctx(ac->module);
231 if (!ares) {
232 return ldb_module_done(ac->req, NULL, NULL,
233 LDB_ERR_OPERATIONS_ERROR);
235 if (ares->error != LDB_SUCCESS &&
236 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
237 return ldb_module_done(ac->req, ares->controls,
238 ares->response, ares->error);
241 ldb_reset_err_string(ldb);
243 switch (ares->type) {
244 case LDB_REPLY_ENTRY:
245 if (ac->search_res != NULL) {
246 ldb_set_errstring(ldb, "Too many results");
247 talloc_free(ares);
248 return ldb_module_done(ac->req, NULL, NULL,
249 LDB_ERR_OPERATIONS_ERROR);
252 ac->search_res = talloc_steal(ac, ares);
253 break;
255 case LDB_REPLY_REFERRAL:
256 /* ignore */
257 talloc_free(ares);
258 break;
260 case LDB_REPLY_DONE:
261 talloc_free(ares);
262 ret = ac->step_fn(ac);
263 if (ret != LDB_SUCCESS) {
264 return ldb_module_done(ac->req, NULL, NULL, ret);
266 break;
269 return LDB_SUCCESS;
272 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
274 struct oc_context *ac;
276 ac = talloc_get_type(req->context, struct oc_context);
278 if (!ares) {
279 return ldb_module_done(ac->req, NULL, NULL,
280 LDB_ERR_OPERATIONS_ERROR);
283 if (ares->type == LDB_REPLY_REFERRAL) {
284 return ldb_module_send_referral(ac->req, ares->referral);
287 if (ares->error != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 if (ares->type != LDB_REPLY_DONE) {
293 talloc_free(ares);
294 return ldb_module_done(ac->req, NULL, NULL,
295 LDB_ERR_OPERATIONS_ERROR);
298 return ldb_module_done(ac->req, ares->controls,
299 ares->response, ares->error);
302 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
304 This should mean that if the parent is:
305 CN=Users,DC=samba,DC=example,DC=com
306 and a proposed child is
307 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
309 The resulting DN should be:
311 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
314 static int fix_dn(struct ldb_context *ldb,
315 TALLOC_CTX *mem_ctx,
316 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
317 struct ldb_dn **fixed_dn)
319 char *upper_rdn_attr;
320 const struct ldb_val *rdn_val;
322 /* Fix up the DN to be in the standard form, taking particular care to
323 * match the parent DN */
324 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
325 if (*fixed_dn == NULL) {
326 return ldb_oom(ldb);
329 /* We need the attribute name in upper case */
330 upper_rdn_attr = strupper_talloc(*fixed_dn,
331 ldb_dn_get_rdn_name(newdn));
332 if (upper_rdn_attr == NULL) {
333 return ldb_oom(ldb);
336 /* Create a new child */
337 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
338 return ldb_operr(ldb);
341 rdn_val = ldb_dn_get_rdn_val(newdn);
342 if (rdn_val == NULL) {
343 return ldb_operr(ldb);
346 #if 0
347 /* the rules for rDN length constraints are more complex than
348 this. Until we understand them we need to leave this
349 constraint out. Otherwise we break replication, as windows
350 does sometimes send us rDNs longer than 64 */
351 if (!rdn_val || rdn_val->length > 64) {
352 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
354 #endif
357 /* And replace it with CN=foo (we need the attribute in upper case) */
358 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
362 static int objectclass_do_add(struct oc_context *ac);
364 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
366 struct ldb_context *ldb;
367 struct ldb_request *search_req;
368 struct oc_context *ac;
369 struct ldb_dn *parent_dn;
370 const struct ldb_val *val;
371 int ret;
372 static const char * const parent_attrs[] = { "objectClass", NULL };
374 ldb = ldb_module_get_ctx(module);
376 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
378 /* do not manipulate our control entries */
379 if (ldb_dn_is_special(req->op.add.message->dn)) {
380 return ldb_next_request(module, req);
383 /* An add operation on the basedn without "NC-add" operation isn't
384 * allowed. */
385 if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
386 unsigned int instanceType;
388 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
389 "instanceType", 0);
390 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
391 char *referral_uri;
392 /* When we are trying to readd the root basedn then
393 * this is denied, but with an interesting mechanism:
394 * there is generated a referral with the last
395 * component value as hostname. */
396 val = ldb_dn_get_component_val(req->op.add.message->dn,
397 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
398 if (val == NULL) {
399 return ldb_operr(ldb);
401 referral_uri = talloc_asprintf(req, "ldap://%s/%s", val->data,
402 ldb_dn_get_linearized(req->op.add.message->dn));
403 if (referral_uri == NULL) {
404 return ldb_module_oom(module);
407 return ldb_module_send_referral(req, referral_uri);
411 ac = oc_init_context(module, req);
412 if (ac == NULL) {
413 return ldb_operr(ldb);
416 /* If there isn't a parent, just go on to the add processing */
417 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
418 return objectclass_do_add(ac);
421 /* get copy of parent DN */
422 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
423 if (parent_dn == NULL) {
424 return ldb_operr(ldb);
427 ret = ldb_build_search_req(&search_req, ldb,
428 ac, parent_dn, LDB_SCOPE_BASE,
429 "(objectClass=*)", parent_attrs,
430 NULL,
431 ac, get_search_callback,
432 req);
433 LDB_REQ_SET_LOCATION(search_req);
434 if (ret != LDB_SUCCESS) {
435 return ret;
438 ac->step_fn = objectclass_do_add;
440 return ldb_next_request(ac->module, search_req);
445 check if this is a special RODC nTDSDSA add
447 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
448 const struct dsdb_class *objectclass)
450 struct ldb_control *rodc_control;
452 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
453 return false;
455 rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
456 if (!rodc_control) {
457 return false;
460 rodc_control->critical = false;
461 return true;
464 static int objectclass_do_add(struct oc_context *ac)
466 struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
467 struct ldb_request *add_req;
468 struct ldb_message_element *objectclass_element, *el;
469 struct ldb_message *msg;
470 TALLOC_CTX *mem_ctx;
471 struct class_list *sorted, *current;
472 const char *rdn_name = NULL;
473 char *value;
474 const struct dsdb_class *objectclass;
475 struct ldb_dn *objectcategory;
476 int32_t systemFlags = 0;
477 unsigned int i, j;
478 bool found;
479 int ret;
481 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
482 if (msg == NULL) {
483 return ldb_module_oom(ac->module);
486 /* Check if we have a valid parent - this check is needed since
487 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
488 if (ac->search_res == NULL) {
489 unsigned int instanceType;
491 /* An add operation on partition DNs without "NC-add" operation
492 * isn't allowed. */
493 instanceType = ldb_msg_find_attr_as_uint(msg, "instanceType",
495 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
496 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
497 ldb_dn_get_linearized(msg->dn));
498 return LDB_ERR_NO_SUCH_OBJECT;
501 /* Don't keep any error messages - we've to add a partition */
502 ldb_set_errstring(ldb, NULL);
503 } else {
504 /* Fix up the DN to be in the standard form, taking
505 * particular care to match the parent DN */
506 ret = fix_dn(ldb, msg,
507 ac->req->op.add.message->dn,
508 ac->search_res->message->dn,
509 &msg->dn);
510 if (ret != LDB_SUCCESS) {
511 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
512 ldb_dn_get_linearized(ac->req->op.add.message->dn));
513 return ret;
517 if (ac->schema != NULL) {
518 objectclass_element = ldb_msg_find_element(msg, "objectClass");
519 if (!objectclass_element) {
520 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
521 ldb_dn_get_linearized(msg->dn));
522 return LDB_ERR_OBJECT_CLASS_VIOLATION;
524 if (objectclass_element->num_values == 0) {
525 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, at least one (structural) objectclass has to be specified!",
526 ldb_dn_get_linearized(msg->dn));
527 return LDB_ERR_CONSTRAINT_VIOLATION;
530 mem_ctx = talloc_new(ac);
531 if (mem_ctx == NULL) {
532 return ldb_module_oom(ac->module);
535 /* Here we do now get the "objectClass" list from the
536 * database. */
537 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
538 objectclass_element, &sorted);
539 if (ret != LDB_SUCCESS) {
540 talloc_free(mem_ctx);
541 return ret;
544 ldb_msg_remove_element(msg, objectclass_element);
546 /* Well, now we shouldn't find any additional "objectClass"
547 * message element (required by the AD specification). */
548 objectclass_element = ldb_msg_find_element(msg, "objectClass");
549 if (objectclass_element != NULL) {
550 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
551 ldb_dn_get_linearized(msg->dn));
552 talloc_free(mem_ctx);
553 return LDB_ERR_OBJECT_CLASS_VIOLATION;
556 /* We must completely replace the existing objectClass entry,
557 * because we need it sorted. */
558 ret = ldb_msg_add_empty(msg, "objectClass", 0,
559 &objectclass_element);
560 if (ret != LDB_SUCCESS) {
561 talloc_free(mem_ctx);
562 return ret;
565 /* Move from the linked list back into an ldb msg */
566 for (current = sorted; current; current = current->next) {
567 const char *objectclass_name = current->objectclass->lDAPDisplayName;
569 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
570 if (ret != LDB_SUCCESS) {
571 ldb_set_errstring(ldb,
572 "objectclass: could not re-add sorted "
573 "objectclass to modify msg");
574 talloc_free(mem_ctx);
575 return ret;
579 talloc_free(mem_ctx);
581 /* Make sure its valid to add an object of this type */
582 objectclass = get_last_structural_class(ac->schema,
583 objectclass_element, ac->req);
584 if(objectclass == NULL) {
585 ldb_asprintf_errstring(ldb,
586 "Failed to find a structural class for %s",
587 ldb_dn_get_linearized(msg->dn));
588 return LDB_ERR_UNWILLING_TO_PERFORM;
591 rdn_name = ldb_dn_get_rdn_name(msg->dn);
592 if (rdn_name == NULL) {
593 return ldb_operr(ldb);
595 found = false;
596 for (i = 0; (!found) && (i < objectclass_element->num_values);
597 i++) {
598 const struct dsdb_class *tmp_class =
599 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
600 &objectclass_element->values[i]);
602 if (tmp_class == NULL) continue;
604 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
605 found = true;
607 if (!found) {
608 ldb_asprintf_errstring(ldb,
609 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
610 rdn_name, objectclass->lDAPDisplayName);
611 return LDB_ERR_NAMING_VIOLATION;
614 if (objectclass->systemOnly &&
615 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
616 !check_rodc_ntdsdsa_add(ac, objectclass)) {
617 ldb_asprintf_errstring(ldb,
618 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
619 objectclass->lDAPDisplayName,
620 ldb_dn_get_linearized(msg->dn));
621 return LDB_ERR_UNWILLING_TO_PERFORM;
624 if (ac->search_res && ac->search_res->message) {
625 struct ldb_message_element *oc_el
626 = ldb_msg_find_element(ac->search_res->message, "objectClass");
628 bool allowed_class = false;
629 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
630 const struct dsdb_class *sclass;
632 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
633 &oc_el->values[i]);
634 if (!sclass) {
635 /* We don't know this class? what is going on? */
636 continue;
638 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
639 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
640 allowed_class = true;
641 break;
646 if (!allowed_class) {
647 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
648 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
649 return LDB_ERR_NAMING_VIOLATION;
653 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
654 "objectCategory");
655 if (objectcategory == NULL) {
656 struct dsdb_extended_dn_store_format *dn_format =
657 talloc_get_type(ldb_module_get_private(ac->module),
658 struct dsdb_extended_dn_store_format);
659 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
660 /* Strip off extended components */
661 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
662 objectclass->defaultObjectCategory);
663 value = ldb_dn_alloc_linearized(msg, dn);
664 talloc_free(dn);
665 } else {
666 value = talloc_strdup(msg,
667 objectclass->defaultObjectCategory);
669 if (value == NULL) {
670 return ldb_module_oom(ac->module);
673 ret = ldb_msg_add_string(msg, "objectCategory", value);
674 if (ret != LDB_SUCCESS) {
675 return ret;
677 } else {
678 const struct dsdb_class *ocClass =
679 dsdb_class_by_cn_ldb_val(ac->schema,
680 ldb_dn_get_rdn_val(objectcategory));
681 if (ocClass != NULL) {
682 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
683 ocClass->defaultObjectCategory);
684 if (ldb_dn_compare(objectcategory, dn) != 0) {
685 ocClass = NULL;
688 talloc_free(objectcategory);
689 if (ocClass == NULL) {
690 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
691 ldb_dn_get_linearized(msg->dn));
692 return LDB_ERR_OBJECT_CLASS_VIOLATION;
696 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
697 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
698 "TRUE");
701 /* There are very special rules for systemFlags, see MS-ADTS
702 * MS-ADTS 3.1.1.5.2.4 */
704 el = ldb_msg_find_element(msg, "systemFlags");
705 if ((el != NULL) && (el->num_values > 1)) {
706 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
707 ldb_dn_get_linearized(msg->dn));
708 return LDB_ERR_CONSTRAINT_VIOLATION;
711 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
713 ldb_msg_remove_attr(msg, "systemFlags");
715 /* Only the following flags may be set by a client */
716 if (ldb_request_get_control(ac->req,
717 LDB_CONTROL_RELAX_OID) == NULL) {
718 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
719 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
720 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
721 | SYSTEM_FLAG_ATTR_IS_RDN );
724 /* But the last one ("ATTR_IS_RDN") is only allowed on
725 * "attributeSchema" objects. So truncate if it does not fit. */
726 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
727 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
730 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
731 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
732 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
733 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
734 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
735 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0)
736 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
737 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
738 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
739 || ldb_attr_cmp(objectclass->lDAPDisplayName, "subnet") == 0
740 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
741 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
742 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
744 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
746 if (el || systemFlags != 0) {
747 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
748 systemFlags);
749 if (ret != LDB_SUCCESS) {
750 return ret;
754 /* make sure that "isCriticalSystemObject" is not specified! */
755 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
756 if ((el != NULL) &&
757 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
758 ldb_set_errstring(ldb,
759 "objectclass: 'isCriticalSystemObject' must not be specified!");
760 return LDB_ERR_UNWILLING_TO_PERFORM;
764 ret = ldb_build_add_req(&add_req, ldb, ac,
765 msg,
766 ac->req->controls,
767 ac, oc_op_callback,
768 ac->req);
769 LDB_REQ_SET_LOCATION(add_req);
770 if (ret != LDB_SUCCESS) {
771 return ret;
774 /* perform the add */
775 return ldb_next_request(ac->module, add_req);
778 static int oc_modify_callback(struct ldb_request *req,
779 struct ldb_reply *ares);
780 static int objectclass_do_mod(struct oc_context *ac);
782 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
784 struct ldb_context *ldb = ldb_module_get_ctx(module);
785 struct ldb_message_element *objectclass_element;
786 struct ldb_message *msg;
787 struct ldb_request *down_req;
788 struct oc_context *ac;
789 bool oc_changes = false;
790 int ret;
792 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
794 /* do not manipulate our control entries */
795 if (ldb_dn_is_special(req->op.mod.message->dn)) {
796 return ldb_next_request(module, req);
799 /* As with the "real" AD we don't accept empty messages */
800 if (req->op.mod.message->num_elements == 0) {
801 ldb_set_errstring(ldb, "objectclass: modify message must have "
802 "elements/attributes!");
803 return LDB_ERR_UNWILLING_TO_PERFORM;
806 ac = oc_init_context(module, req);
807 if (ac == NULL) {
808 return ldb_operr(ldb);
811 /* Without schema, there isn't much to do here */
812 if (ac->schema == NULL) {
813 talloc_free(ac);
814 return ldb_next_request(module, req);
817 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
818 if (msg == NULL) {
819 return ldb_module_oom(ac->module);
822 /* For now change everything except the objectclasses */
824 objectclass_element = ldb_msg_find_element(msg, "objectClass");
825 if (objectclass_element != NULL) {
826 ldb_msg_remove_attr(msg, "objectClass");
827 oc_changes = true;
830 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
831 * only on application NCs - not on the default ones */
832 if (oc_changes &&
833 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
834 struct ldb_dn *nc_root;
836 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
837 &nc_root);
838 if (ret != LDB_SUCCESS) {
839 return ret;
842 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
843 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
844 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
845 ldb_set_errstring(ldb,
846 "objectclass: object class changes on objects under the standard name contexts not allowed!");
847 return LDB_ERR_UNWILLING_TO_PERFORM;
850 talloc_free(nc_root);
853 ret = ldb_build_mod_req(&down_req, ldb, ac,
854 msg,
855 req->controls, ac,
856 oc_changes ? oc_modify_callback : oc_op_callback,
857 req);
858 LDB_REQ_SET_LOCATION(down_req);
859 if (ret != LDB_SUCCESS) {
860 return ret;
863 return ldb_next_request(module, down_req);
866 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
868 static const char * const attrs[] = { "objectClass", NULL };
869 struct ldb_context *ldb;
870 struct ldb_request *search_req;
871 struct oc_context *ac;
872 int ret;
874 ac = talloc_get_type(req->context, struct oc_context);
875 ldb = ldb_module_get_ctx(ac->module);
877 if (!ares) {
878 return ldb_module_done(ac->req, NULL, NULL,
879 LDB_ERR_OPERATIONS_ERROR);
882 if (ares->type == LDB_REPLY_REFERRAL) {
883 return ldb_module_send_referral(ac->req, ares->referral);
886 if (ares->error != LDB_SUCCESS) {
887 return ldb_module_done(ac->req, ares->controls,
888 ares->response, ares->error);
891 if (ares->type != LDB_REPLY_DONE) {
892 talloc_free(ares);
893 return ldb_module_done(ac->req, NULL, NULL,
894 LDB_ERR_OPERATIONS_ERROR);
897 talloc_free(ares);
899 /* this looks up the real existing object for fetching some important
900 * information (objectclasses) */
901 ret = ldb_build_search_req(&search_req, ldb,
902 ac, ac->req->op.mod.message->dn,
903 LDB_SCOPE_BASE,
904 "(objectClass=*)",
905 attrs, NULL,
906 ac, get_search_callback,
907 ac->req);
908 LDB_REQ_SET_LOCATION(search_req);
909 if (ret != LDB_SUCCESS) {
910 return ldb_module_done(ac->req, NULL, NULL, ret);
913 ac->step_fn = objectclass_do_mod;
915 ret = ldb_next_request(ac->module, search_req);
916 if (ret != LDB_SUCCESS) {
917 return ldb_module_done(ac->req, NULL, NULL, ret);
920 return LDB_SUCCESS;
923 static int objectclass_do_mod(struct oc_context *ac)
925 struct ldb_context *ldb;
926 struct ldb_request *mod_req;
927 char *value;
928 struct ldb_message_element *oc_el_entry, *oc_el_change;
929 struct ldb_val *vals;
930 struct ldb_message *msg;
931 TALLOC_CTX *mem_ctx;
932 struct class_list *sorted, *current;
933 const struct dsdb_class *objectclass;
934 unsigned int i, j, k;
935 bool found, replace = false;
936 int ret;
938 ldb = ldb_module_get_ctx(ac->module);
940 /* we should always have a valid entry when we enter here */
941 if (ac->search_res == NULL) {
942 return ldb_operr(ldb);
945 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
946 "objectClass");
947 if (oc_el_entry == NULL) {
948 /* existing entry without a valid object class? */
949 return ldb_operr(ldb);
952 /* use a new message structure */
953 msg = ldb_msg_new(ac);
954 if (msg == NULL) {
955 return ldb_module_oom(ac->module);
958 msg->dn = ac->req->op.mod.message->dn;
960 mem_ctx = talloc_new(ac);
961 if (mem_ctx == NULL) {
962 return ldb_module_oom(ac->module);
965 /* We've to walk over all "objectClass" message elements */
966 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
967 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
968 "objectClass") != 0) {
969 continue;
972 oc_el_change = &ac->req->op.mod.message->elements[k];
974 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
975 case LDB_FLAG_MOD_ADD:
976 /* Merge the two message elements */
977 for (i = 0; i < oc_el_change->num_values; i++) {
978 for (j = 0; j < oc_el_entry->num_values; j++) {
979 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
980 (char *)oc_el_entry->values[j].data) == 0) {
981 ldb_asprintf_errstring(ldb,
982 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
983 (int)oc_el_change->values[i].length,
984 (const char *)oc_el_change->values[i].data);
985 talloc_free(mem_ctx);
986 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
989 /* append the new object class value - code was
990 * copied from "ldb_msg_add_value" */
991 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
992 struct ldb_val,
993 oc_el_entry->num_values + 1);
994 if (vals == NULL) {
995 talloc_free(mem_ctx);
996 return ldb_module_oom(ac->module);
998 oc_el_entry->values = vals;
999 oc_el_entry->values[oc_el_entry->num_values] =
1000 oc_el_change->values[i];
1001 ++(oc_el_entry->num_values);
1004 objectclass = get_last_structural_class(ac->schema,
1005 oc_el_change, ac->req);
1006 if (objectclass != NULL) {
1007 ldb_asprintf_errstring(ldb,
1008 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1009 objectclass->lDAPDisplayName);
1010 talloc_free(mem_ctx);
1011 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1014 /* Now do the sorting */
1015 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1016 oc_el_entry, &sorted);
1017 if (ret != LDB_SUCCESS) {
1018 talloc_free(mem_ctx);
1019 return ret;
1022 break;
1024 case LDB_FLAG_MOD_REPLACE:
1025 /* Do the sorting for the change message element */
1026 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1027 oc_el_change, &sorted);
1028 if (ret != LDB_SUCCESS) {
1029 talloc_free(mem_ctx);
1030 return ret;
1033 /* this is a replace */
1034 replace = true;
1036 break;
1038 case LDB_FLAG_MOD_DELETE:
1039 /* get the actual top-most structural objectclass */
1040 objectclass = get_last_structural_class(ac->schema,
1041 oc_el_entry, ac->req);
1042 if (objectclass == NULL) {
1043 /* no structural objectclass? */
1044 talloc_free(mem_ctx);
1045 return ldb_operr(ldb);
1048 /* Merge the two message elements */
1049 for (i = 0; i < oc_el_change->num_values; i++) {
1050 found = false;
1051 for (j = 0; j < oc_el_entry->num_values; j++) {
1052 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1053 (char *)oc_el_entry->values[j].data) == 0) {
1054 found = true;
1055 /* delete the object class value
1056 * - code was copied from
1057 * "ldb_msg_remove_element" */
1058 if (j != oc_el_entry->num_values - 1) {
1059 memmove(&oc_el_entry->values[j],
1060 &oc_el_entry->values[j+1],
1061 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1063 --(oc_el_entry->num_values);
1064 break;
1067 if (!found) {
1068 /* we cannot delete a not existing
1069 * object class */
1070 ldb_asprintf_errstring(ldb,
1071 "objectclass: cannot delete this objectclass: '%.*s'!",
1072 (int)oc_el_change->values[i].length,
1073 (const char *)oc_el_change->values[i].data);
1074 talloc_free(mem_ctx);
1075 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1079 /* Make sure that the top-most structural object class
1080 * hasn't been deleted */
1081 found = false;
1082 for (i = 0; i < oc_el_entry->num_values; i++) {
1083 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1084 (char *)oc_el_entry->values[i].data) == 0) {
1085 found = true;
1086 break;
1089 if (!found) {
1090 ldb_asprintf_errstring(ldb,
1091 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1092 objectclass->lDAPDisplayName);
1093 talloc_free(mem_ctx);
1094 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1097 /* Now do the sorting */
1098 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1099 oc_el_entry, &sorted);
1100 if (ret != LDB_SUCCESS) {
1101 talloc_free(mem_ctx);
1102 return ret;
1105 break;
1108 /* (Re)-add an empty "objectClass" attribute on the object
1109 * classes change message "msg". */
1110 ldb_msg_remove_attr(msg, "objectClass");
1111 ret = ldb_msg_add_empty(msg, "objectClass",
1112 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1113 if (ret != LDB_SUCCESS) {
1114 talloc_free(mem_ctx);
1115 return ret;
1118 /* Move from the linked list back into an ldb msg */
1119 for (current = sorted; current; current = current->next) {
1120 value = talloc_strdup(msg,
1121 current->objectclass->lDAPDisplayName);
1122 if (value == NULL) {
1123 talloc_free(mem_ctx);
1124 return ldb_module_oom(ac->module);
1126 ret = ldb_msg_add_string(msg, "objectClass", value);
1127 if (ret != LDB_SUCCESS) {
1128 ldb_set_errstring(ldb,
1129 "objectclass: could not re-add sorted objectclasses!");
1130 talloc_free(mem_ctx);
1131 return ret;
1135 if (replace) {
1136 /* Well, on replace we are nearly done: we have to test
1137 * if the change and entry message element are identical
1138 * ly. We can use "ldb_msg_element_compare" since now
1139 * the specified objectclasses match for sure in case.
1141 ret = ldb_msg_element_compare(oc_el_entry,
1142 oc_el_change);
1143 if (ret == 0) {
1144 ret = ldb_msg_element_compare(oc_el_change,
1145 oc_el_entry);
1147 if (ret == 0) {
1148 /* they are the same so we are done in this
1149 * case */
1150 talloc_free(mem_ctx);
1151 return ldb_module_done(ac->req, NULL, NULL,
1152 LDB_SUCCESS);
1153 } else {
1154 ldb_set_errstring(ldb,
1155 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1156 talloc_free(mem_ctx);
1157 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1161 /* Now we've applied all changes from "oc_el_change" to
1162 * "oc_el_entry" therefore the new "oc_el_entry" will be
1163 * "oc_el_change". */
1164 oc_el_entry = oc_el_change;
1167 talloc_free(mem_ctx);
1169 /* Now we have the real and definitive change left to do */
1171 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1172 msg,
1173 ac->req->controls,
1174 ac, oc_op_callback,
1175 ac->req);
1176 LDB_REQ_SET_LOCATION(mod_req);
1177 if (ret != LDB_SUCCESS) {
1178 return ret;
1181 return ldb_next_request(ac->module, mod_req);
1184 static int objectclass_do_rename(struct oc_context *ac);
1186 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1188 static const char * const attrs[] = { "objectClass", NULL };
1189 struct ldb_context *ldb;
1190 struct ldb_request *search_req;
1191 struct oc_context *ac;
1192 struct ldb_dn *parent_dn;
1193 int ret;
1195 ldb = ldb_module_get_ctx(module);
1197 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1199 /* do not manipulate our control entries */
1200 if (ldb_dn_is_special(req->op.rename.olddn)) {
1201 return ldb_next_request(module, req);
1204 ac = oc_init_context(module, req);
1205 if (ac == NULL) {
1206 return ldb_operr(ldb);
1209 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1210 if (parent_dn == NULL) {
1211 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1212 ldb_dn_get_linearized(req->op.rename.olddn));
1213 return LDB_ERR_NO_SUCH_OBJECT;
1216 /* this looks up the parent object for fetching some important
1217 * information (objectclasses, DN normalisation...) */
1218 ret = ldb_build_search_req(&search_req, ldb,
1219 ac, parent_dn, LDB_SCOPE_BASE,
1220 "(objectClass=*)",
1221 attrs, NULL,
1222 ac, get_search_callback,
1223 req);
1224 LDB_REQ_SET_LOCATION(search_req);
1225 if (ret != LDB_SUCCESS) {
1226 return ret;
1229 /* we have to add the show recycled control, as otherwise DRS
1230 deletes will be refused as we will think the target parent
1231 does not exist */
1232 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1233 false, NULL);
1235 if (ret != LDB_SUCCESS) {
1236 return ret;
1239 ac->step_fn = objectclass_do_rename;
1241 return ldb_next_request(ac->module, search_req);
1244 static int objectclass_do_rename2(struct oc_context *ac);
1246 static int objectclass_do_rename(struct oc_context *ac)
1248 static const char * const attrs[] = { "objectClass", NULL };
1249 struct ldb_context *ldb;
1250 struct ldb_request *search_req;
1251 int ret;
1253 ldb = ldb_module_get_ctx(ac->module);
1255 /* Check if we have a valid parent - this check is needed since
1256 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1257 if (ac->search_res == NULL) {
1258 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1259 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1260 return LDB_ERR_OTHER;
1263 /* now assign "search_res2" to the parent entry to have "search_res"
1264 * free for another lookup */
1265 ac->search_res2 = ac->search_res;
1266 ac->search_res = NULL;
1268 /* this looks up the real existing object for fetching some important
1269 * information (objectclasses) */
1270 ret = ldb_build_search_req(&search_req, ldb,
1271 ac, ac->req->op.rename.olddn,
1272 LDB_SCOPE_BASE,
1273 "(objectClass=*)",
1274 attrs, NULL,
1275 ac, get_search_callback,
1276 ac->req);
1277 LDB_REQ_SET_LOCATION(search_req);
1278 if (ret != LDB_SUCCESS) {
1279 return ret;
1282 ac->step_fn = objectclass_do_rename2;
1284 return ldb_next_request(ac->module, search_req);
1287 static int objectclass_do_rename2(struct oc_context *ac)
1289 struct ldb_context *ldb;
1290 struct ldb_request *rename_req;
1291 struct ldb_dn *fixed_dn;
1292 int ret;
1294 ldb = ldb_module_get_ctx(ac->module);
1296 /* Check if we have a valid entry - this check is needed since
1297 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1298 if (ac->search_res == NULL) {
1299 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1300 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1301 return LDB_ERR_NO_SUCH_OBJECT;
1304 if (ac->schema != NULL) {
1305 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1306 const struct dsdb_class *objectclass;
1307 const char *rdn_name;
1308 bool allowed_class = false;
1309 unsigned int i, j;
1310 bool found;
1312 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1313 "objectClass");
1314 if (oc_el_entry == NULL) {
1315 /* existing entry without a valid object class? */
1316 return ldb_operr(ldb);
1318 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1319 if (objectclass == NULL) {
1320 /* existing entry without a valid object class? */
1321 return ldb_operr(ldb);
1324 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1325 if (rdn_name == NULL) {
1326 return ldb_operr(ldb);
1328 found = false;
1329 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1330 const struct dsdb_class *tmp_class =
1331 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1332 &oc_el_entry->values[i]);
1334 if (tmp_class == NULL) continue;
1336 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1337 found = true;
1339 if (!found) {
1340 ldb_asprintf_errstring(ldb,
1341 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1342 rdn_name, objectclass->lDAPDisplayName);
1343 return LDB_ERR_UNWILLING_TO_PERFORM;
1346 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1347 "objectClass");
1348 if (oc_el_parent == NULL) {
1349 /* existing entry without a valid object class? */
1350 return ldb_operr(ldb);
1353 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1354 const struct dsdb_class *sclass;
1356 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1357 &oc_el_parent->values[i]);
1358 if (!sclass) {
1359 /* We don't know this class? what is going on? */
1360 continue;
1362 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1363 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1364 allowed_class = true;
1365 break;
1370 if (!allowed_class) {
1371 ldb_asprintf_errstring(ldb,
1372 "objectclass: structural objectClass %s is not a valid child class for %s",
1373 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1374 return LDB_ERR_NAMING_VIOLATION;
1378 /* Ensure we are not trying to rename it to be a child of itself */
1379 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1380 ac->req->op.rename.newdn) == 0) &&
1381 (ldb_dn_compare(ac->req->op.rename.olddn,
1382 ac->req->op.rename.newdn) != 0)) {
1383 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1384 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1385 return LDB_ERR_UNWILLING_TO_PERFORM;
1388 /* Fix up the DN to be in the standard form, taking
1389 * particular care to match the parent DN */
1390 ret = fix_dn(ldb, ac,
1391 ac->req->op.rename.newdn,
1392 ac->search_res2->message->dn,
1393 &fixed_dn);
1394 if (ret != LDB_SUCCESS) {
1395 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1396 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1397 return ret;
1401 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1402 ac->req->op.rename.olddn, fixed_dn,
1403 ac->req->controls,
1404 ac, oc_op_callback,
1405 ac->req);
1406 LDB_REQ_SET_LOCATION(rename_req);
1407 if (ret != LDB_SUCCESS) {
1408 return ret;
1411 /* perform the rename */
1412 return ldb_next_request(ac->module, rename_req);
1415 static int objectclass_do_delete(struct oc_context *ac);
1417 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1419 static const char * const attrs[] = { "nCName", "objectClass",
1420 "systemFlags",
1421 "isDeleted",
1422 "isCriticalSystemObject", NULL };
1423 struct ldb_context *ldb;
1424 struct ldb_request *search_req;
1425 struct oc_context *ac;
1426 int ret;
1428 ldb = ldb_module_get_ctx(module);
1430 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1432 /* do not manipulate our control entries */
1433 if (ldb_dn_is_special(req->op.del.dn)) {
1434 return ldb_next_request(module, req);
1437 /* Bypass the constraint checks when we do have the "RELAX" control
1438 * set. */
1439 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1440 return ldb_next_request(module, req);
1443 ac = oc_init_context(module, req);
1444 if (ac == NULL) {
1445 return ldb_operr(ldb);
1448 /* this looks up the entry object for fetching some important
1449 * information (object classes, system flags...) */
1450 ret = ldb_build_search_req(&search_req, ldb,
1451 ac, req->op.del.dn, LDB_SCOPE_BASE,
1452 "(objectClass=*)",
1453 attrs, req->controls,
1454 ac, get_search_callback,
1455 req);
1456 LDB_REQ_SET_LOCATION(search_req);
1457 if (ret != LDB_SUCCESS) {
1458 return ret;
1461 ac->step_fn = objectclass_do_delete;
1463 return ldb_next_request(ac->module, search_req);
1466 static int objectclass_do_delete(struct oc_context *ac)
1468 struct ldb_context *ldb;
1469 struct ldb_dn *dn;
1470 int32_t systemFlags;
1471 bool isCriticalSystemObject;
1472 int ret;
1474 ldb = ldb_module_get_ctx(ac->module);
1476 /* Check if we have a valid entry - this check is needed since
1477 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1478 if (ac->search_res == NULL) {
1479 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1480 ldb_dn_get_linearized(ac->req->op.del.dn));
1481 return LDB_ERR_NO_SUCH_OBJECT;
1484 /* DC's ntDSDSA object */
1485 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1486 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1487 ldb_dn_get_linearized(ac->req->op.del.dn));
1488 return LDB_ERR_UNWILLING_TO_PERFORM;
1491 /* DC's rIDSet object */
1492 /* Perform this check only when it does exist - this is needed in order
1493 * to don't let existing provisions break. */
1494 ret = samdb_rid_set_dn(ldb, ac, &dn);
1495 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1496 return ret;
1498 if (ret == LDB_SUCCESS) {
1499 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1500 talloc_free(dn);
1501 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1502 ldb_dn_get_linearized(ac->req->op.del.dn));
1503 return LDB_ERR_UNWILLING_TO_PERFORM;
1505 talloc_free(dn);
1508 /* Only trusted request from system account are allowed to delete
1509 * deleted objects.
1511 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1512 (ldb_req_is_untrusted(ac->req) ||
1513 !dsdb_module_am_system(ac->module))) {
1514 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1515 ldb_dn_get_linearized(ac->req->op.del.dn));
1516 return LDB_ERR_UNWILLING_TO_PERFORM;
1519 /* crossRef objects regarding config, schema and default domain NCs */
1520 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1521 "crossRef") != NULL) {
1522 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1523 "nCName");
1524 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1525 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1526 talloc_free(dn);
1528 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1529 ldb_dn_get_linearized(ac->req->op.del.dn));
1530 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1532 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1533 talloc_free(dn);
1535 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1536 ldb_dn_get_linearized(ac->req->op.del.dn));
1537 return LDB_ERR_UNWILLING_TO_PERFORM;
1539 talloc_free(dn);
1542 /* systemFlags */
1544 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1545 "systemFlags", 0);
1546 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1547 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1548 ldb_dn_get_linearized(ac->req->op.del.dn));
1549 return LDB_ERR_UNWILLING_TO_PERFORM;
1552 /* isCriticalSystemObject - but this only applies on tree delete
1553 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1554 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1555 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1556 "isCriticalSystemObject", false);
1557 if (isCriticalSystemObject) {
1558 ldb_asprintf_errstring(ldb,
1559 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1560 ldb_dn_get_linearized(ac->req->op.del.dn));
1561 return LDB_ERR_UNWILLING_TO_PERFORM;
1565 return ldb_next_request(ac->module, ac->req);
1568 static int objectclass_init(struct ldb_module *module)
1570 struct ldb_context *ldb = ldb_module_get_ctx(module);
1571 int ret;
1573 /* Init everything else */
1574 ret = ldb_next_init(module);
1575 if (ret != LDB_SUCCESS) {
1576 return ret;
1579 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1580 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1582 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1583 if (ret != LDB_SUCCESS) {
1584 ldb_debug(ldb, LDB_DEBUG_ERROR,
1585 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1586 return ldb_operr(ldb);
1589 return ret;
1592 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1593 .name = "objectclass",
1594 .add = objectclass_add,
1595 .modify = objectclass_modify,
1596 .rename = objectclass_rename,
1597 .del = objectclass_delete,
1598 .init_context = objectclass_init
1601 int ldb_objectclass_module_init(const char *version)
1603 LDB_MODULE_CHECK_VERSION(version);
1604 return ldb_register_module(&ldb_objectclass_module_ops);