s4-dsdb: Use controls provided during the request while searching for object to delete
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blob7ae90d353a3ce80fce62250a02249a7dac269da2
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
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 "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 (strcasecmp(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, NULL);
559 if (ret != LDB_SUCCESS) {
560 talloc_free(mem_ctx);
561 return ret;
564 /* Move from the linked list back into an ldb msg */
565 for (current = sorted; current; current = current->next) {
566 const char *objectclass_name = current->objectclass->lDAPDisplayName;
568 ret = ldb_msg_add_string(msg, "objectClass", objectclass_name);
569 if (ret != LDB_SUCCESS) {
570 ldb_set_errstring(ldb,
571 "objectclass: could not re-add sorted "
572 "objectclass to modify msg");
573 talloc_free(mem_ctx);
574 return ret;
578 talloc_free(mem_ctx);
580 /* Retrive the message again so get_last_structural_class works */
581 objectclass_element = ldb_msg_find_element(msg, "objectClass");
583 /* Make sure its valid to add an object of this type */
584 objectclass = get_last_structural_class(ac->schema,
585 objectclass_element, ac->req);
586 if(objectclass == NULL) {
587 ldb_asprintf_errstring(ldb,
588 "Failed to find a structural class for %s",
589 ldb_dn_get_linearized(msg->dn));
590 return LDB_ERR_UNWILLING_TO_PERFORM;
593 rdn_name = ldb_dn_get_rdn_name(msg->dn);
594 if (rdn_name == NULL) {
595 return ldb_operr(ldb);
597 found = false;
598 for (i = 0; (!found) && (i < objectclass_element->num_values);
599 i++) {
600 const struct dsdb_class *tmp_class =
601 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
602 &objectclass_element->values[i]);
604 if (tmp_class == NULL) continue;
606 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
607 found = true;
609 if (!found) {
610 ldb_asprintf_errstring(ldb,
611 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
612 rdn_name, objectclass->lDAPDisplayName);
613 return LDB_ERR_NAMING_VIOLATION;
616 if (objectclass->systemOnly &&
617 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
618 !check_rodc_ntdsdsa_add(ac, objectclass)) {
619 ldb_asprintf_errstring(ldb,
620 "objectclass: object class '%s' is system-only, rejecting creation of '%s'!",
621 objectclass->lDAPDisplayName,
622 ldb_dn_get_linearized(msg->dn));
623 return LDB_ERR_UNWILLING_TO_PERFORM;
626 if (ac->search_res && ac->search_res->message) {
627 struct ldb_message_element *oc_el
628 = ldb_msg_find_element(ac->search_res->message, "objectClass");
630 bool allowed_class = false;
631 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
632 const struct dsdb_class *sclass;
634 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
635 &oc_el->values[i]);
636 if (!sclass) {
637 /* We don't know this class? what is going on? */
638 continue;
640 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
641 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
642 allowed_class = true;
643 break;
648 if (!allowed_class) {
649 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
650 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
651 return LDB_ERR_NAMING_VIOLATION;
655 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
656 "objectCategory");
657 if (objectcategory == NULL) {
658 struct dsdb_extended_dn_store_format *dn_format =
659 talloc_get_type(ldb_module_get_private(ac->module),
660 struct dsdb_extended_dn_store_format);
661 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
662 /* Strip off extended components */
663 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
664 objectclass->defaultObjectCategory);
665 value = ldb_dn_alloc_linearized(msg, dn);
666 talloc_free(dn);
667 } else {
668 value = talloc_strdup(msg,
669 objectclass->defaultObjectCategory);
671 if (value == NULL) {
672 return ldb_module_oom(ac->module);
675 ret = ldb_msg_add_string(msg, "objectCategory", value);
676 if (ret != LDB_SUCCESS) {
677 return ret;
679 } else {
680 const struct dsdb_class *ocClass =
681 dsdb_class_by_cn_ldb_val(ac->schema,
682 ldb_dn_get_rdn_val(objectcategory));
683 if (ocClass != NULL) {
684 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
685 ocClass->defaultObjectCategory);
686 if (ldb_dn_compare(objectcategory, dn) != 0) {
687 ocClass = NULL;
690 talloc_free(objectcategory);
691 if (ocClass == NULL) {
692 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
693 ldb_dn_get_linearized(msg->dn));
694 return LDB_ERR_OBJECT_CLASS_VIOLATION;
698 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
699 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
700 "TRUE");
703 /* There are very special rules for systemFlags, see MS-ADTS
704 * MS-ADTS 3.1.1.5.2.4 */
706 el = ldb_msg_find_element(msg, "systemFlags");
707 if ((el != NULL) && (el->num_values > 1)) {
708 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
709 ldb_dn_get_linearized(msg->dn));
710 return LDB_ERR_CONSTRAINT_VIOLATION;
713 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
715 ldb_msg_remove_attr(msg, "systemFlags");
717 /* Only the following flags may be set by a client */
718 if (ldb_request_get_control(ac->req,
719 LDB_CONTROL_RELAX_OID) == NULL) {
720 systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME
721 | SYSTEM_FLAG_CONFIG_ALLOW_MOVE
722 | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE
723 | SYSTEM_FLAG_ATTR_IS_RDN );
726 /* But the last one ("ATTR_IS_RDN") is only allowed on
727 * "attributeSchema" objects. So truncate if it does not fit. */
728 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") != 0) {
729 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
732 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
733 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
734 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
735 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serversContainer") == 0
736 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSDSA") == 0) {
737 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
739 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 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);
745 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
747 if (el || systemFlags != 0) {
748 ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
749 systemFlags);
750 if (ret != LDB_SUCCESS) {
751 return ret;
755 /* make sure that "isCriticalSystemObject" is not specified! */
756 el = ldb_msg_find_element(msg, "isCriticalSystemObject");
757 if ((el != NULL) &&
758 !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
759 ldb_set_errstring(ldb,
760 "objectclass: 'isCriticalSystemObject' must not be specified!");
761 return LDB_ERR_UNWILLING_TO_PERFORM;
765 ret = ldb_build_add_req(&add_req, ldb, ac,
766 msg,
767 ac->req->controls,
768 ac, oc_op_callback,
769 ac->req);
770 LDB_REQ_SET_LOCATION(add_req);
771 if (ret != LDB_SUCCESS) {
772 return ret;
775 /* perform the add */
776 return ldb_next_request(ac->module, add_req);
779 static int oc_modify_callback(struct ldb_request *req,
780 struct ldb_reply *ares);
781 static int objectclass_do_mod(struct oc_context *ac);
783 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
785 struct ldb_context *ldb = ldb_module_get_ctx(module);
786 struct ldb_message_element *objectclass_element;
787 struct ldb_message *msg;
788 struct ldb_request *down_req;
789 struct oc_context *ac;
790 bool oc_changes = false;
791 int ret;
793 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
795 /* do not manipulate our control entries */
796 if (ldb_dn_is_special(req->op.mod.message->dn)) {
797 return ldb_next_request(module, req);
800 /* As with the "real" AD we don't accept empty messages */
801 if (req->op.mod.message->num_elements == 0) {
802 ldb_set_errstring(ldb, "objectclass: modify message must have "
803 "elements/attributes!");
804 return LDB_ERR_UNWILLING_TO_PERFORM;
807 ac = oc_init_context(module, req);
808 if (ac == NULL) {
809 return ldb_operr(ldb);
812 /* Without schema, there isn't much to do here */
813 if (ac->schema == NULL) {
814 talloc_free(ac);
815 return ldb_next_request(module, req);
818 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
819 if (msg == NULL) {
820 return ldb_module_oom(ac->module);
823 /* For now change everything except the objectclasses */
825 objectclass_element = ldb_msg_find_element(msg, "objectClass");
826 if (objectclass_element != NULL) {
827 ldb_msg_remove_attr(msg, "objectClass");
828 oc_changes = true;
831 /* MS-ADTS 3.1.1.5.3.5 - on a forest level < 2003 we do allow updates
832 * only on application NCs - not on the default ones */
833 if (oc_changes &&
834 (dsdb_forest_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
835 struct ldb_dn *nc_root;
837 ret = dsdb_find_nc_root(ldb, ac, req->op.mod.message->dn,
838 &nc_root);
839 if (ret != LDB_SUCCESS) {
840 return ret;
843 if ((ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) ||
844 (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) ||
845 (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0)) {
846 ldb_set_errstring(ldb,
847 "objectclass: object class changes on objects under the standard name contexts not allowed!");
848 return LDB_ERR_UNWILLING_TO_PERFORM;
851 talloc_free(nc_root);
854 ret = ldb_build_mod_req(&down_req, ldb, ac,
855 msg,
856 req->controls, ac,
857 oc_changes ? oc_modify_callback : oc_op_callback,
858 req);
859 LDB_REQ_SET_LOCATION(down_req);
860 if (ret != LDB_SUCCESS) {
861 return ret;
864 return ldb_next_request(module, down_req);
867 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
869 static const char * const attrs[] = { "objectClass", NULL };
870 struct ldb_context *ldb;
871 struct ldb_request *search_req;
872 struct oc_context *ac;
873 int ret;
875 ac = talloc_get_type(req->context, struct oc_context);
876 ldb = ldb_module_get_ctx(ac->module);
878 if (!ares) {
879 return ldb_module_done(ac->req, NULL, NULL,
880 LDB_ERR_OPERATIONS_ERROR);
883 if (ares->type == LDB_REPLY_REFERRAL) {
884 return ldb_module_send_referral(ac->req, ares->referral);
887 if (ares->error != LDB_SUCCESS) {
888 return ldb_module_done(ac->req, ares->controls,
889 ares->response, ares->error);
892 if (ares->type != LDB_REPLY_DONE) {
893 talloc_free(ares);
894 return ldb_module_done(ac->req, NULL, NULL,
895 LDB_ERR_OPERATIONS_ERROR);
898 talloc_free(ares);
900 /* this looks up the real existing object for fetching some important
901 * information (objectclasses) */
902 ret = ldb_build_search_req(&search_req, ldb,
903 ac, ac->req->op.mod.message->dn,
904 LDB_SCOPE_BASE,
905 "(objectClass=*)",
906 attrs, NULL,
907 ac, get_search_callback,
908 ac->req);
909 LDB_REQ_SET_LOCATION(search_req);
910 if (ret != LDB_SUCCESS) {
911 return ldb_module_done(ac->req, NULL, NULL, ret);
914 ac->step_fn = objectclass_do_mod;
916 ret = ldb_next_request(ac->module, search_req);
917 if (ret != LDB_SUCCESS) {
918 return ldb_module_done(ac->req, NULL, NULL, ret);
921 return LDB_SUCCESS;
924 static int objectclass_do_mod(struct oc_context *ac)
926 struct ldb_context *ldb;
927 struct ldb_request *mod_req;
928 char *value;
929 struct ldb_message_element *oc_el_entry, *oc_el_change;
930 struct ldb_val *vals;
931 struct ldb_message *msg;
932 TALLOC_CTX *mem_ctx;
933 struct class_list *sorted, *current;
934 const struct dsdb_class *objectclass;
935 unsigned int i, j, k;
936 bool found, replace = false;
937 int ret;
939 ldb = ldb_module_get_ctx(ac->module);
941 /* we should always have a valid entry when we enter here */
942 if (ac->search_res == NULL) {
943 return ldb_operr(ldb);
946 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
947 "objectClass");
948 if (oc_el_entry == NULL) {
949 /* existing entry without a valid object class? */
950 return ldb_operr(ldb);
953 /* use a new message structure */
954 msg = ldb_msg_new(ac);
955 if (msg == NULL) {
956 return ldb_module_oom(ac->module);
959 msg->dn = ac->req->op.mod.message->dn;
961 mem_ctx = talloc_new(ac);
962 if (mem_ctx == NULL) {
963 return ldb_module_oom(ac->module);
966 /* We've to walk over all "objectClass" message elements */
967 for (k = 0; k < ac->req->op.mod.message->num_elements; k++) {
968 if (ldb_attr_cmp(ac->req->op.mod.message->elements[k].name,
969 "objectClass") != 0) {
970 continue;
973 oc_el_change = &ac->req->op.mod.message->elements[k];
975 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
976 case LDB_FLAG_MOD_ADD:
977 /* Merge the two message elements */
978 for (i = 0; i < oc_el_change->num_values; i++) {
979 for (j = 0; j < oc_el_entry->num_values; j++) {
980 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
981 (char *)oc_el_entry->values[j].data) == 0) {
982 ldb_asprintf_errstring(ldb,
983 "objectclass: cannot re-add an existing objectclass: '%.*s'!",
984 (int)oc_el_change->values[i].length,
985 (const char *)oc_el_change->values[i].data);
986 talloc_free(mem_ctx);
987 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
990 /* append the new object class value - code was
991 * copied from "ldb_msg_add_value" */
992 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
993 struct ldb_val,
994 oc_el_entry->num_values + 1);
995 if (vals == NULL) {
996 talloc_free(mem_ctx);
997 return ldb_module_oom(ac->module);
999 oc_el_entry->values = vals;
1000 oc_el_entry->values[oc_el_entry->num_values] =
1001 oc_el_change->values[i];
1002 ++(oc_el_entry->num_values);
1005 objectclass = get_last_structural_class(ac->schema,
1006 oc_el_change, ac->req);
1007 if (objectclass != NULL) {
1008 ldb_asprintf_errstring(ldb,
1009 "objectclass: cannot add a new top-most structural objectclass '%s'!",
1010 objectclass->lDAPDisplayName);
1011 talloc_free(mem_ctx);
1012 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1015 /* Now do the sorting */
1016 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1017 oc_el_entry, &sorted);
1018 if (ret != LDB_SUCCESS) {
1019 talloc_free(mem_ctx);
1020 return ret;
1023 break;
1025 case LDB_FLAG_MOD_REPLACE:
1026 /* Do the sorting for the change message element */
1027 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1028 oc_el_change, &sorted);
1029 if (ret != LDB_SUCCESS) {
1030 talloc_free(mem_ctx);
1031 return ret;
1034 /* this is a replace */
1035 replace = true;
1037 break;
1039 case LDB_FLAG_MOD_DELETE:
1040 /* get the actual top-most structural objectclass */
1041 objectclass = get_last_structural_class(ac->schema,
1042 oc_el_entry, ac->req);
1043 if (objectclass == NULL) {
1044 /* no structural objectclass? */
1045 talloc_free(mem_ctx);
1046 return ldb_operr(ldb);
1049 /* Merge the two message elements */
1050 for (i = 0; i < oc_el_change->num_values; i++) {
1051 found = false;
1052 for (j = 0; j < oc_el_entry->num_values; j++) {
1053 if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
1054 (char *)oc_el_entry->values[j].data) == 0) {
1055 found = true;
1056 /* delete the object class value
1057 * - code was copied from
1058 * "ldb_msg_remove_element" */
1059 if (j != oc_el_entry->num_values - 1) {
1060 memmove(&oc_el_entry->values[j],
1061 &oc_el_entry->values[j+1],
1062 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1064 --(oc_el_entry->num_values);
1065 break;
1068 if (!found) {
1069 /* we cannot delete a not existing
1070 * object class */
1071 ldb_asprintf_errstring(ldb,
1072 "objectclass: cannot delete this objectclass: '%.*s'!",
1073 (int)oc_el_change->values[i].length,
1074 (const char *)oc_el_change->values[i].data);
1075 talloc_free(mem_ctx);
1076 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1080 /* Make sure that the top-most structural object class
1081 * hasn't been deleted */
1082 found = false;
1083 for (i = 0; i < oc_el_entry->num_values; i++) {
1084 if (ldb_attr_cmp(objectclass->lDAPDisplayName,
1085 (char *)oc_el_entry->values[i].data) == 0) {
1086 found = true;
1087 break;
1090 if (!found) {
1091 ldb_asprintf_errstring(ldb,
1092 "objectclass: cannot delete the top-most structural objectclass '%s'!",
1093 objectclass->lDAPDisplayName);
1094 talloc_free(mem_ctx);
1095 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1098 /* Now do the sorting */
1099 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1100 oc_el_entry, &sorted);
1101 if (ret != LDB_SUCCESS) {
1102 talloc_free(mem_ctx);
1103 return ret;
1106 break;
1109 /* (Re)-add an empty "objectClass" attribute on the object
1110 * classes change message "msg". */
1111 ldb_msg_remove_attr(msg, "objectClass");
1112 ret = ldb_msg_add_empty(msg, "objectClass",
1113 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1114 if (ret != LDB_SUCCESS) {
1115 talloc_free(mem_ctx);
1116 return ret;
1119 /* Move from the linked list back into an ldb msg */
1120 for (current = sorted; current; current = current->next) {
1121 value = talloc_strdup(msg,
1122 current->objectclass->lDAPDisplayName);
1123 if (value == NULL) {
1124 talloc_free(mem_ctx);
1125 return ldb_module_oom(ac->module);
1127 ret = ldb_msg_add_string(msg, "objectClass", value);
1128 if (ret != LDB_SUCCESS) {
1129 ldb_set_errstring(ldb,
1130 "objectclass: could not re-add sorted objectclasses!");
1131 talloc_free(mem_ctx);
1132 return ret;
1136 if (replace) {
1137 /* Well, on replace we are nearly done: we have to test
1138 * if the change and entry message element are identical
1139 * ly. We can use "ldb_msg_element_compare" since now
1140 * the specified objectclasses match for sure in case.
1142 ret = ldb_msg_element_compare(oc_el_entry,
1143 oc_el_change);
1144 if (ret == 0) {
1145 ret = ldb_msg_element_compare(oc_el_change,
1146 oc_el_entry);
1148 if (ret == 0) {
1149 /* they are the same so we are done in this
1150 * case */
1151 talloc_free(mem_ctx);
1152 return ldb_module_done(ac->req, NULL, NULL,
1153 LDB_SUCCESS);
1154 } else {
1155 ldb_set_errstring(ldb,
1156 "objectclass: the specified objectclasses are not exactly the same as on the entry!");
1157 talloc_free(mem_ctx);
1158 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1162 /* Now we've applied all changes from "oc_el_change" to
1163 * "oc_el_entry" therefore the new "oc_el_entry" will be
1164 * "oc_el_change". */
1165 oc_el_entry = oc_el_change;
1168 talloc_free(mem_ctx);
1170 /* Now we have the real and definitive change left to do */
1172 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1173 msg,
1174 ac->req->controls,
1175 ac, oc_op_callback,
1176 ac->req);
1177 LDB_REQ_SET_LOCATION(mod_req);
1178 if (ret != LDB_SUCCESS) {
1179 return ret;
1182 return ldb_next_request(ac->module, mod_req);
1185 static int objectclass_do_rename(struct oc_context *ac);
1187 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1189 static const char * const attrs[] = { "objectClass", NULL };
1190 struct ldb_context *ldb;
1191 struct ldb_request *search_req;
1192 struct oc_context *ac;
1193 struct ldb_dn *parent_dn;
1194 int ret;
1196 ldb = ldb_module_get_ctx(module);
1198 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1200 /* do not manipulate our control entries */
1201 if (ldb_dn_is_special(req->op.rename.olddn)) {
1202 return ldb_next_request(module, req);
1205 ac = oc_init_context(module, req);
1206 if (ac == NULL) {
1207 return ldb_operr(ldb);
1210 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1211 if (parent_dn == NULL) {
1212 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1213 ldb_dn_get_linearized(req->op.rename.olddn));
1214 return LDB_ERR_NO_SUCH_OBJECT;
1217 /* this looks up the parent object for fetching some important
1218 * information (objectclasses, DN normalisation...) */
1219 ret = ldb_build_search_req(&search_req, ldb,
1220 ac, parent_dn, LDB_SCOPE_BASE,
1221 "(objectClass=*)",
1222 attrs, NULL,
1223 ac, get_search_callback,
1224 req);
1225 LDB_REQ_SET_LOCATION(search_req);
1226 if (ret != LDB_SUCCESS) {
1227 return ret;
1230 /* we have to add the show recycled control, as otherwise DRS
1231 deletes will be refused as we will think the target parent
1232 does not exist */
1233 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
1234 false, NULL);
1236 if (ret != LDB_SUCCESS) {
1237 return ret;
1240 ac->step_fn = objectclass_do_rename;
1242 return ldb_next_request(ac->module, search_req);
1245 static int objectclass_do_rename2(struct oc_context *ac);
1247 static int objectclass_do_rename(struct oc_context *ac)
1249 static const char * const attrs[] = { "objectClass", NULL };
1250 struct ldb_context *ldb;
1251 struct ldb_request *search_req;
1252 int ret;
1254 ldb = ldb_module_get_ctx(ac->module);
1256 /* Check if we have a valid parent - this check is needed since
1257 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1258 if (ac->search_res == NULL) {
1259 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1260 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1261 return LDB_ERR_OTHER;
1264 /* now assign "search_res2" to the parent entry to have "search_res"
1265 * free for another lookup */
1266 ac->search_res2 = ac->search_res;
1267 ac->search_res = NULL;
1269 /* this looks up the real existing object for fetching some important
1270 * information (objectclasses) */
1271 ret = ldb_build_search_req(&search_req, ldb,
1272 ac, ac->req->op.rename.olddn,
1273 LDB_SCOPE_BASE,
1274 "(objectClass=*)",
1275 attrs, NULL,
1276 ac, get_search_callback,
1277 ac->req);
1278 LDB_REQ_SET_LOCATION(search_req);
1279 if (ret != LDB_SUCCESS) {
1280 return ret;
1283 ac->step_fn = objectclass_do_rename2;
1285 return ldb_next_request(ac->module, search_req);
1288 static int objectclass_do_rename2(struct oc_context *ac)
1290 struct ldb_context *ldb;
1291 struct ldb_request *rename_req;
1292 struct ldb_dn *fixed_dn;
1293 int ret;
1295 ldb = ldb_module_get_ctx(ac->module);
1297 /* Check if we have a valid entry - this check is needed since
1298 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1299 if (ac->search_res == NULL) {
1300 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1301 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1302 return LDB_ERR_NO_SUCH_OBJECT;
1305 if (ac->schema != NULL) {
1306 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1307 const struct dsdb_class *objectclass;
1308 const char *rdn_name;
1309 bool allowed_class = false;
1310 unsigned int i, j;
1311 bool found;
1313 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1314 "objectClass");
1315 if (oc_el_entry == NULL) {
1316 /* existing entry without a valid object class? */
1317 return ldb_operr(ldb);
1319 objectclass = get_last_structural_class(ac->schema, oc_el_entry, ac->req);
1320 if (objectclass == NULL) {
1321 /* existing entry without a valid object class? */
1322 return ldb_operr(ldb);
1325 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1326 if (rdn_name == NULL) {
1327 return ldb_operr(ldb);
1329 found = false;
1330 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1331 const struct dsdb_class *tmp_class =
1332 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1333 &oc_el_entry->values[i]);
1335 if (tmp_class == NULL) continue;
1337 if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1338 found = true;
1340 if (!found) {
1341 ldb_asprintf_errstring(ldb,
1342 "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1343 rdn_name, objectclass->lDAPDisplayName);
1344 return LDB_ERR_UNWILLING_TO_PERFORM;
1347 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1348 "objectClass");
1349 if (oc_el_parent == NULL) {
1350 /* existing entry without a valid object class? */
1351 return ldb_operr(ldb);
1354 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1355 const struct dsdb_class *sclass;
1357 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1358 &oc_el_parent->values[i]);
1359 if (!sclass) {
1360 /* We don't know this class? what is going on? */
1361 continue;
1363 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1364 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1365 allowed_class = true;
1366 break;
1371 if (!allowed_class) {
1372 ldb_asprintf_errstring(ldb,
1373 "objectclass: structural objectClass %s is not a valid child class for %s",
1374 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1375 return LDB_ERR_NAMING_VIOLATION;
1379 /* Ensure we are not trying to rename it to be a child of itself */
1380 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1381 ac->req->op.rename.newdn) == 0) &&
1382 (ldb_dn_compare(ac->req->op.rename.olddn,
1383 ac->req->op.rename.newdn) != 0)) {
1384 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1385 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1386 return LDB_ERR_UNWILLING_TO_PERFORM;
1389 /* Fix up the DN to be in the standard form, taking
1390 * particular care to match the parent DN */
1391 ret = fix_dn(ldb, ac,
1392 ac->req->op.rename.newdn,
1393 ac->search_res2->message->dn,
1394 &fixed_dn);
1395 if (ret != LDB_SUCCESS) {
1396 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1397 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1398 return ret;
1402 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1403 ac->req->op.rename.olddn, fixed_dn,
1404 ac->req->controls,
1405 ac, oc_op_callback,
1406 ac->req);
1407 LDB_REQ_SET_LOCATION(rename_req);
1408 if (ret != LDB_SUCCESS) {
1409 return ret;
1412 /* perform the rename */
1413 return ldb_next_request(ac->module, rename_req);
1416 static int objectclass_do_delete(struct oc_context *ac);
1418 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1420 static const char * const attrs[] = { "nCName", "objectClass",
1421 "systemFlags",
1422 "isDeleted",
1423 "isCriticalSystemObject", NULL };
1424 struct ldb_context *ldb;
1425 struct ldb_request *search_req;
1426 struct oc_context *ac;
1427 int ret;
1429 ldb = ldb_module_get_ctx(module);
1431 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1433 /* do not manipulate our control entries */
1434 if (ldb_dn_is_special(req->op.del.dn)) {
1435 return ldb_next_request(module, req);
1438 /* Bypass the constraint checks when we do have the "RELAX" control
1439 * set. */
1440 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1441 return ldb_next_request(module, req);
1444 ac = oc_init_context(module, req);
1445 if (ac == NULL) {
1446 return ldb_operr(ldb);
1449 /* this looks up the entry object for fetching some important
1450 * information (object classes, system flags...) */
1451 ret = ldb_build_search_req(&search_req, ldb,
1452 ac, req->op.del.dn, LDB_SCOPE_BASE,
1453 "(objectClass=*)",
1454 attrs, req->controls,
1455 ac, get_search_callback,
1456 req);
1457 LDB_REQ_SET_LOCATION(search_req);
1458 if (ret != LDB_SUCCESS) {
1459 return ret;
1462 ac->step_fn = objectclass_do_delete;
1464 return ldb_next_request(ac->module, search_req);
1467 static int objectclass_do_delete(struct oc_context *ac)
1469 struct ldb_context *ldb;
1470 struct ldb_dn *dn;
1471 int32_t systemFlags;
1472 bool isCriticalSystemObject;
1473 int ret;
1475 ldb = ldb_module_get_ctx(ac->module);
1477 /* Check if we have a valid entry - this check is needed since
1478 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1479 if (ac->search_res == NULL) {
1480 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1481 ldb_dn_get_linearized(ac->req->op.del.dn));
1482 return LDB_ERR_NO_SUCH_OBJECT;
1485 /* DC's ntDSDSA object */
1486 if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1487 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1488 ldb_dn_get_linearized(ac->req->op.del.dn));
1489 return LDB_ERR_UNWILLING_TO_PERFORM;
1492 /* DC's rIDSet object */
1493 /* Perform this check only when it does exist - this is needed in order
1494 * to don't let existing provisions break. */
1495 ret = samdb_rid_set_dn(ldb, ac, &dn);
1496 if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1497 return ret;
1499 if (ret == LDB_SUCCESS) {
1500 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1501 talloc_free(dn);
1502 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1503 ldb_dn_get_linearized(ac->req->op.del.dn));
1504 return LDB_ERR_UNWILLING_TO_PERFORM;
1506 talloc_free(dn);
1509 /* Only trusted request from system account are allowed to delete
1510 * deleted objects.
1512 if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1513 (ldb_req_is_untrusted(ac->req) ||
1514 !dsdb_module_am_system(ac->module))) {
1515 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1516 ldb_dn_get_linearized(ac->req->op.del.dn));
1517 return LDB_ERR_UNWILLING_TO_PERFORM;
1520 /* crossRef objects regarding config, schema and default domain NCs */
1521 if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1522 "crossRef") != NULL) {
1523 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1524 "nCName");
1525 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1526 (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1527 talloc_free(dn);
1529 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1530 ldb_dn_get_linearized(ac->req->op.del.dn));
1531 return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1533 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1534 talloc_free(dn);
1536 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1537 ldb_dn_get_linearized(ac->req->op.del.dn));
1538 return LDB_ERR_UNWILLING_TO_PERFORM;
1540 talloc_free(dn);
1543 /* systemFlags */
1545 systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1546 "systemFlags", 0);
1547 if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1548 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1549 ldb_dn_get_linearized(ac->req->op.del.dn));
1550 return LDB_ERR_UNWILLING_TO_PERFORM;
1553 /* isCriticalSystemObject - but this only applies on tree delete
1554 * operations - MS-ADTS 3.1.1.5.5.7.2 */
1555 if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1556 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1557 "isCriticalSystemObject", false);
1558 if (isCriticalSystemObject) {
1559 ldb_asprintf_errstring(ldb,
1560 "objectclass: Cannot tree-delete %s, it's a critical system object!",
1561 ldb_dn_get_linearized(ac->req->op.del.dn));
1562 return LDB_ERR_UNWILLING_TO_PERFORM;
1566 return ldb_next_request(ac->module, ac->req);
1569 static int objectclass_init(struct ldb_module *module)
1571 struct ldb_context *ldb = ldb_module_get_ctx(module);
1572 int ret;
1574 /* Init everything else */
1575 ret = ldb_next_init(module);
1576 if (ret != LDB_SUCCESS) {
1577 return ret;
1580 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1581 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1583 ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1584 if (ret != LDB_SUCCESS) {
1585 ldb_debug(ldb, LDB_DEBUG_ERROR,
1586 "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1587 return ldb_operr(ldb);
1590 return ret;
1593 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1594 .name = "objectclass",
1595 .add = objectclass_add,
1596 .modify = objectclass_modify,
1597 .rename = objectclass_rename,
1598 .del = objectclass_delete,
1599 .init_context = objectclass_init
1602 int ldb_objectclass_module_init(const char *version)
1604 LDB_MODULE_CHECK_VERSION(version);
1605 return ldb_register_module(&ldb_objectclass_module_ops);