s4:objectclass LDB module - Prevent write operations on constructed attributes
[Samba/ekacnet.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blob82b8835b0b700c5df4de675c9af44ae15cddbd35
1 /*
2 ldb database library
4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * Name: ldb
24 * Component: objectClass sorting module
26 * Description:
27 * - sort the objectClass attribute into the class
28 * hierarchy,
29 * - fix DNs and attributes into 'standard' case
30 * - Add objectCategory and ntSecurityDescriptor defaults
32 * Author: Andrew Bartlett
36 #include "includes.h"
37 #include "ldb_module.h"
38 #include "dlinklist.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "librpc/ndr/libndr.h"
41 #include "librpc/gen_ndr/ndr_security.h"
42 #include "libcli/security/security.h"
43 #include "auth/auth.h"
44 #include "param/param.h"
45 #include "../libds/common/flags.h"
47 struct oc_context {
49 struct ldb_module *module;
50 struct ldb_request *req;
52 struct ldb_reply *search_res;
54 int (*step_fn)(struct oc_context *);
57 struct class_list {
58 struct class_list *prev, *next;
59 const struct dsdb_class *objectclass;
62 static struct oc_context *oc_init_context(struct ldb_module *module,
63 struct ldb_request *req)
65 struct ldb_context *ldb;
66 struct oc_context *ac;
68 ldb = ldb_module_get_ctx(module);
70 ac = talloc_zero(req, struct oc_context);
71 if (ac == NULL) {
72 ldb_set_errstring(ldb, "Out of Memory");
73 return NULL;
76 ac->module = module;
77 ac->req = req;
79 return ac;
82 static int objectclass_do_add(struct oc_context *ac);
84 /* Sort objectClasses into correct order, and validate that all
85 * objectClasses specified actually exist in the schema
88 static int objectclass_sort(struct ldb_module *module,
89 const struct dsdb_schema *schema,
90 TALLOC_CTX *mem_ctx,
91 struct ldb_message_element *objectclass_element,
92 struct class_list **sorted_out)
94 struct ldb_context *ldb;
95 int i;
96 int layer;
97 struct class_list *sorted = NULL, *parent_class = NULL,
98 *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent;
100 ldb = ldb_module_get_ctx(module);
102 /* DESIGN:
104 * We work on 4 different 'bins' (implemented here as linked lists):
106 * * sorted: the eventual list, in the order we wish to push
107 * into the database. This is the only ordered list.
109 * * parent_class: The current parent class 'bin' we are
110 * trying to find subclasses for
112 * * subclass: The subclasses we have found so far
114 * * unsorted: The remaining objectClasses
116 * The process is a matter of filtering objectClasses up from
117 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
119 * We start with 'top' (found and promoted to parent_class
120 * initially). Then we find (in unsorted) all the direct
121 * subclasses of 'top'. parent_classes is concatenated onto
122 * the end of 'sorted', and subclass becomes the list in
123 * parent_class.
125 * We then repeat, until we find no more subclasses. Any left
126 * over classes are added to the end.
130 /* Firstly, dump all the objectClass elements into the
131 * unsorted bin, except for 'top', which is special */
132 for (i=0; i < objectclass_element->num_values; i++) {
133 current = talloc(mem_ctx, struct class_list);
134 if (!current) {
135 ldb_oom(ldb);
136 return LDB_ERR_OPERATIONS_ERROR;
138 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
139 if (!current->objectclass) {
140 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
141 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
142 /* This looks weird, but windows apparently returns this for invalid objectClass values */
143 return LDB_ERR_NO_SUCH_ATTRIBUTE;
144 } else if (current->objectclass->isDefunct) {
145 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
146 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
147 /* This looks weird, but windows apparently returns this for invalid objectClass values */
148 return LDB_ERR_NO_SUCH_ATTRIBUTE;
151 /* this is the root of the tree. We will start
152 * looking for subclasses from here */
153 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) {
154 DLIST_ADD_END(parent_class, current, struct class_list *);
155 } else {
156 DLIST_ADD_END(unsorted, current, struct class_list *);
160 if (parent_class == NULL) {
161 current = talloc(mem_ctx, struct class_list);
162 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
163 DLIST_ADD_END(parent_class, current, struct class_list *);
166 /* For each object: find parent chain */
167 for (current = unsorted; schema && current; current = current->next) {
168 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
169 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
170 break;
173 /* If we didn't get to the end of the list, we need to add this parent */
174 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
175 continue;
178 new_parent = talloc(mem_ctx, struct class_list);
179 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
180 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
183 /* DEBUGGING aid: how many layers are we down now? */
184 layer = 0;
185 do {
186 layer++;
187 /* Find all the subclasses of classes in the
188 * parent_classes. Push them onto the subclass list */
190 /* Ensure we don't bother if there are no unsorted entries left */
191 for (current = parent_class; schema && unsorted && current; current = current->next) {
192 /* Walk the list of possible subclasses in unsorted */
193 for (poss_subclass = unsorted; poss_subclass; ) {
194 struct class_list *next;
196 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
197 next = poss_subclass->next;
199 if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) {
200 DLIST_REMOVE(unsorted, poss_subclass);
201 DLIST_ADD(subclass, poss_subclass);
203 break;
205 poss_subclass = next;
209 /* Now push the parent_classes as sorted, we are done with
210 these. Add to the END of the list by concatenation */
211 DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
213 /* and now find subclasses of these */
214 parent_class = subclass;
215 subclass = NULL;
217 /* If we didn't find any subclasses we will fall out
218 * the bottom here */
219 } while (parent_class);
221 if (!unsorted) {
222 *sorted_out = sorted;
223 return LDB_SUCCESS;
226 if (!schema) {
227 /* If we don't have schema yet, then just merge the lists again */
228 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
229 *sorted_out = sorted;
230 return LDB_SUCCESS;
233 /* This shouldn't happen, and would break MMC, perhaps there
234 * was no 'top', a conflict in the objectClasses or some other
235 * schema error?
237 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
238 return LDB_ERR_OBJECT_CLASS_VIOLATION;
241 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
243 struct ldb_context *ldb;
244 struct oc_context *ac;
245 int ret;
247 ac = talloc_get_type(req->context, struct oc_context);
248 ldb = ldb_module_get_ctx(ac->module);
250 if (!ares) {
251 return ldb_module_done(ac->req, NULL, NULL,
252 LDB_ERR_OPERATIONS_ERROR);
254 if (ares->error != LDB_SUCCESS &&
255 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
256 return ldb_module_done(ac->req, ares->controls,
257 ares->response, ares->error);
260 ldb_reset_err_string(ldb);
262 switch (ares->type) {
263 case LDB_REPLY_ENTRY:
264 if (ac->search_res != NULL) {
265 ldb_set_errstring(ldb, "Too many results");
266 talloc_free(ares);
267 return ldb_module_done(ac->req, NULL, NULL,
268 LDB_ERR_OPERATIONS_ERROR);
271 ac->search_res = talloc_steal(ac, ares);
272 break;
274 case LDB_REPLY_REFERRAL:
275 /* ignore */
276 talloc_free(ares);
277 break;
279 case LDB_REPLY_DONE:
280 talloc_free(ares);
281 ret = ac->step_fn(ac);
282 if (ret != LDB_SUCCESS) {
283 return ldb_module_done(ac->req, NULL, NULL, ret);
285 break;
288 return LDB_SUCCESS;
291 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
293 struct oc_context *ac;
295 ac = talloc_get_type(req->context, struct oc_context);
297 if (!ares) {
298 return ldb_module_done(ac->req, NULL, NULL,
299 LDB_ERR_OPERATIONS_ERROR);
301 if (ares->error != LDB_SUCCESS) {
302 return ldb_module_done(ac->req, ares->controls,
303 ares->response, ares->error);
306 if (ares->type != LDB_REPLY_DONE) {
307 talloc_free(ares);
308 return ldb_module_done(ac->req, NULL, NULL,
309 LDB_ERR_OPERATIONS_ERROR);
312 return ldb_module_done(ac->req, ares->controls,
313 ares->response, ares->error);
316 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
318 This should mean that if the parent is:
319 CN=Users,DC=samba,DC=example,DC=com
320 and a proposed child is
321 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
323 The resulting DN should be:
325 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
328 static int fix_dn(TALLOC_CTX *mem_ctx,
329 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
330 struct ldb_dn **fixed_dn)
332 char *upper_rdn_attr;
333 const struct ldb_val *rdn_val;
335 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
336 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
338 /* We need the attribute name in upper case */
339 upper_rdn_attr = strupper_talloc(*fixed_dn,
340 ldb_dn_get_rdn_name(newdn));
341 if (!upper_rdn_attr) {
342 return LDB_ERR_OPERATIONS_ERROR;
345 /* Create a new child */
346 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
347 return LDB_ERR_OPERATIONS_ERROR;
351 rdn_val = ldb_dn_get_rdn_val(newdn);
353 #if 0
354 /* the rules for rDN length constraints are more complex than
355 this. Until we understand them we need to leave this
356 constraint out. Otherwise we break replication, as windows
357 does sometimes send us rDNs longer than 64 */
358 if (!rdn_val || rdn_val->length > 64) {
359 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
361 #endif
364 /* And replace it with CN=foo (we need the attribute in upper case */
365 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
368 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
369 static int fix_check_attributes(struct ldb_context *ldb,
370 const struct dsdb_schema *schema,
371 struct ldb_message *msg,
372 enum ldb_request_type op)
374 unsigned int i;
375 for (i=0; i < msg->num_elements; i++) {
376 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
377 /* Add in a very special case for 'clearTextPassword',
378 * which is used for internal processing only, and is
379 * not presented in the schema */
380 if (!attribute) {
381 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
382 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
383 /* Apparently Windows sends exactly this behaviour */
384 return LDB_ERR_NO_SUCH_ATTRIBUTE;
386 } else {
387 msg->elements[i].name = attribute->lDAPDisplayName;
389 /* We have to deny write operations on constructed attributes */
390 if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
391 if (op == LDB_ADD) {
392 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
393 } else {
394 return LDB_ERR_CONSTRAINT_VIOLATION;
401 return LDB_SUCCESS;
404 static int objectclass_do_add(struct oc_context *ac);
406 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
408 struct ldb_context *ldb;
409 struct ldb_request *search_req;
410 struct oc_context *ac;
411 struct ldb_dn *parent_dn;
412 int ret;
413 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
415 ldb = ldb_module_get_ctx(module);
417 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
419 /* do not manipulate our control entries */
420 if (ldb_dn_is_special(req->op.add.message->dn)) {
421 return ldb_next_request(module, req);
424 /* the objectClass must be specified on add */
425 if (ldb_msg_find_element(req->op.add.message,
426 "objectClass") == NULL) {
427 return LDB_ERR_OBJECT_CLASS_VIOLATION;
430 ac = oc_init_context(module, req);
431 if (ac == NULL) {
432 return LDB_ERR_OPERATIONS_ERROR;
435 /* If there isn't a parent, just go on to the add processing */
436 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
437 return objectclass_do_add(ac);
440 /* get copy of parent DN */
441 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
442 if (parent_dn == NULL) {
443 ldb_oom(ldb);
444 return LDB_ERR_OPERATIONS_ERROR;
447 ret = ldb_build_search_req(&search_req, ldb,
448 ac, parent_dn, LDB_SCOPE_BASE,
449 "(objectClass=*)", parent_attrs,
450 NULL,
451 ac, get_search_callback,
452 req);
453 if (ret != LDB_SUCCESS) {
454 return ret;
456 talloc_steal(search_req, parent_dn);
458 ac->step_fn = objectclass_do_add;
460 return ldb_next_request(ac->module, search_req);
463 static int objectclass_do_add(struct oc_context *ac)
465 struct ldb_context *ldb;
466 const struct dsdb_schema *schema;
467 struct ldb_request *add_req;
468 char *value;
469 struct ldb_message_element *objectclass_element;
470 struct ldb_message *msg;
471 TALLOC_CTX *mem_ctx;
472 struct class_list *sorted, *current;
473 int ret;
475 ldb = ldb_module_get_ctx(ac->module);
476 schema = dsdb_get_schema(ldb);
478 mem_ctx = talloc_new(ac);
479 if (mem_ctx == NULL) {
480 return LDB_ERR_OPERATIONS_ERROR;
483 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
485 /* Check we have a valid parent */
486 if (ac->search_res == NULL) {
487 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
488 msg->dn) == 0) {
489 /* Allow the tree to be started */
491 /* but don't keep any error string, it's meaningless */
492 ldb_set_errstring(ldb, NULL);
493 } else {
494 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
495 ldb_dn_get_linearized(msg->dn));
496 talloc_free(mem_ctx);
497 return LDB_ERR_NO_SUCH_OBJECT;
499 } else {
501 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
502 ret = fix_dn(msg,
503 ac->req->op.add.message->dn,
504 ac->search_res->message->dn,
505 &msg->dn);
507 if (ret != LDB_SUCCESS) {
508 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
509 ldb_dn_get_linearized(ac->req->op.add.message->dn));
510 talloc_free(mem_ctx);
511 return ret;
515 if (schema) {
516 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
517 if (ret != LDB_SUCCESS) {
518 talloc_free(mem_ctx);
519 return ret;
522 /* This is now the objectClass list from the database */
523 objectclass_element = ldb_msg_find_element(msg, "objectClass");
525 if (!objectclass_element) {
526 /* Where did it go? bail now... */
527 talloc_free(mem_ctx);
528 return LDB_ERR_OPERATIONS_ERROR;
530 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
531 if (ret != LDB_SUCCESS) {
532 talloc_free(mem_ctx);
533 return ret;
536 ldb_msg_remove_attr(msg, "objectClass");
537 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
539 if (ret != LDB_SUCCESS) {
540 talloc_free(mem_ctx);
541 return ret;
544 /* We must completely replace the existing objectClass entry,
545 * because we need it sorted */
547 /* Move from the linked list back into an ldb msg */
548 for (current = sorted; current; current = current->next) {
549 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
550 if (value == NULL) {
551 ldb_oom(ldb);
552 talloc_free(mem_ctx);
553 return LDB_ERR_OPERATIONS_ERROR;
555 ret = ldb_msg_add_string(msg, "objectClass", value);
556 if (ret != LDB_SUCCESS) {
557 ldb_set_errstring(ldb,
558 "objectclass: could not re-add sorted "
559 "objectclass to modify msg");
560 talloc_free(mem_ctx);
561 return ret;
563 /* Last one is the critical one */
564 if (!current->next) {
565 struct ldb_message_element *el;
566 int32_t systemFlags = 0;
567 const char *rdn_name = ldb_dn_get_rdn_name(msg->dn);
568 if (current->objectclass->rDNAttID
569 && ldb_attr_cmp(rdn_name, current->objectclass->rDNAttID) != 0) {
570 ldb_asprintf_errstring(ldb,
571 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
572 rdn_name, current->objectclass->lDAPDisplayName, current->objectclass->rDNAttID);
573 return LDB_ERR_NAMING_VIOLATION;
576 if (ac->search_res && ac->search_res->message) {
577 struct ldb_message_element *oc_el
578 = ldb_msg_find_element(ac->search_res->message, "objectClass");
580 bool allowed_class = false;
581 int i, j;
582 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
583 const struct dsdb_class *sclass;
585 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
586 if (!sclass) {
587 /* We don't know this class? what is going on? */
588 continue;
590 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
591 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
592 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
593 allowed_class = true;
594 break;
597 } else {
598 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
599 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
600 allowed_class = true;
601 break;
607 if (!allowed_class) {
608 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
609 current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
610 return LDB_ERR_NAMING_VIOLATION;
614 if (current->objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
615 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
616 current->objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
617 return LDB_ERR_UNWILLING_TO_PERFORM;
620 if (!ldb_msg_find_element(msg, "objectCategory")) {
621 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
622 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
623 /* Strip off extended components */
624 struct ldb_dn *dn = ldb_dn_new(msg, ldb, current->objectclass->defaultObjectCategory);
625 value = ldb_dn_alloc_linearized(msg, dn);
626 talloc_free(dn);
627 } else {
628 value = talloc_strdup(msg, current->objectclass->defaultObjectCategory);
630 if (value == NULL) {
631 ldb_oom(ldb);
632 talloc_free(mem_ctx);
633 return LDB_ERR_OPERATIONS_ERROR;
635 ldb_msg_add_string(msg, "objectCategory", value);
637 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
638 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
639 "TRUE");
642 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
643 el = ldb_msg_find_element(msg, "systemFlags");
645 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
647 if (el) {
648 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
649 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
650 ldb_msg_remove_element(msg, el);
653 /* This flag is only allowed on attributeSchema objects */
654 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) {
655 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
658 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "server") == 0) {
659 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
660 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "site") == 0
661 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "serverContainer") == 0
662 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
663 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
665 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0
666 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0
667 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
668 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
671 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
673 if (el || systemFlags != 0) {
674 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
680 talloc_free(mem_ctx);
681 ret = ldb_msg_sanity_check(ldb, msg);
684 if (ret != LDB_SUCCESS) {
685 return ret;
688 ret = ldb_build_add_req(&add_req, ldb, ac,
689 msg,
690 ac->req->controls,
691 ac, oc_op_callback,
692 ac->req);
693 if (ret != LDB_SUCCESS) {
694 return ret;
697 /* perform the add */
698 return ldb_next_request(ac->module, add_req);
701 static int oc_modify_callback(struct ldb_request *req,
702 struct ldb_reply *ares);
703 static int objectclass_do_mod(struct oc_context *ac);
705 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
707 struct ldb_context *ldb = ldb_module_get_ctx(module);
708 struct ldb_message_element *objectclass_element;
709 struct ldb_message *msg;
710 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
711 struct class_list *sorted, *current;
712 struct ldb_request *down_req;
713 struct oc_context *ac;
714 TALLOC_CTX *mem_ctx;
715 char *value;
716 int ret;
718 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
720 /* do not manipulate our control entries */
721 if (ldb_dn_is_special(req->op.mod.message->dn)) {
722 return ldb_next_request(module, req);
725 /* Without schema, there isn't much to do here */
726 if (!schema) {
727 return ldb_next_request(module, req);
730 /* As with the "real" AD we don't accept empty messages */
731 if (req->op.mod.message->num_elements == 0) {
732 ldb_set_errstring(ldb, "objectclass: modify message must have "
733 "elements/attributes!");
734 return LDB_ERR_UNWILLING_TO_PERFORM;
737 ac = oc_init_context(module, req);
738 if (ac == NULL) {
739 return LDB_ERR_OPERATIONS_ERROR;
742 /* If no part of this touches the objectClass, then we don't
743 * need to make any changes. */
744 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
746 /* If the only operation is the deletion of the objectClass
747 * then go on with just fixing the attribute case */
748 if (!objectclass_element) {
749 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
750 if (msg == NULL) {
751 return LDB_ERR_OPERATIONS_ERROR;
754 ret = fix_check_attributes(ldb, schema, msg, req->operation);
755 if (ret != LDB_SUCCESS) {
756 return ret;
759 ret = ldb_build_mod_req(&down_req, ldb, ac,
760 msg,
761 req->controls,
762 ac, oc_op_callback,
763 req);
764 if (ret != LDB_SUCCESS) {
765 return ret;
768 /* go on with the call chain */
769 return ldb_next_request(module, down_req);
772 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
773 case LDB_FLAG_MOD_DELETE:
774 if (objectclass_element->num_values == 0) {
775 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
777 break;
779 case LDB_FLAG_MOD_REPLACE:
780 mem_ctx = talloc_new(ac);
781 if (mem_ctx == NULL) {
782 return LDB_ERR_OPERATIONS_ERROR;
785 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
786 if (msg == NULL) {
787 talloc_free(mem_ctx);
788 return LDB_ERR_OPERATIONS_ERROR;
791 ret = fix_check_attributes(ldb, schema, msg, req->operation);
792 if (ret != LDB_SUCCESS) {
793 talloc_free(mem_ctx);
794 return ret;
797 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
798 if (ret != LDB_SUCCESS) {
799 talloc_free(mem_ctx);
800 return ret;
803 /* We must completely replace the existing objectClass entry,
804 * because we need it sorted */
806 ldb_msg_remove_attr(msg, "objectClass");
807 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
809 if (ret != LDB_SUCCESS) {
810 talloc_free(mem_ctx);
811 return ret;
814 /* Move from the linked list back into an ldb msg */
815 for (current = sorted; current; current = current->next) {
816 /* copy the value as this string is on the schema
817 * context and we can't rely on it not changing
818 * before the operation is over */
819 value = talloc_strdup(msg,
820 current->objectclass->lDAPDisplayName);
821 if (value == NULL) {
822 ldb_oom(ldb);
823 talloc_free(mem_ctx);
824 return LDB_ERR_OPERATIONS_ERROR;
826 ret = ldb_msg_add_string(msg, "objectClass", value);
827 if (ret != LDB_SUCCESS) {
828 ldb_set_errstring(ldb,
829 "objectclass: could not re-add sorted "
830 "objectclass to modify msg");
831 talloc_free(mem_ctx);
832 return ret;
836 talloc_free(mem_ctx);
838 ret = ldb_msg_sanity_check(ldb, msg);
839 if (ret != LDB_SUCCESS) {
840 return ret;
843 ret = ldb_build_mod_req(&down_req, ldb, ac,
844 msg,
845 req->controls,
846 ac, oc_op_callback,
847 req);
848 if (ret != LDB_SUCCESS) {
849 return ret;
852 /* go on with the call chain */
853 return ldb_next_request(module, down_req);
856 /* This isn't the default branch of the switch, but a 'in any
857 * other case'. When a delete isn't for all objectClasses for
858 * example
861 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
862 if (msg == NULL) {
863 ldb_oom(ldb);
864 return LDB_ERR_OPERATIONS_ERROR;
867 ret = fix_check_attributes(ldb, schema, msg, req->operation);
868 if (ret != LDB_SUCCESS) {
869 ldb_oom(ldb);
870 return ret;
873 ret = ldb_build_mod_req(&down_req, ldb, ac,
874 msg,
875 req->controls,
876 ac, oc_modify_callback,
877 req);
878 if (ret != LDB_SUCCESS) {
879 return ret;
882 return ldb_next_request(module, down_req);
885 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
887 struct ldb_context *ldb;
888 static const char * const attrs[] = { "objectClass", NULL };
889 struct ldb_request *search_req;
890 struct oc_context *ac;
891 int ret;
893 ac = talloc_get_type(req->context, struct oc_context);
894 ldb = ldb_module_get_ctx(ac->module);
896 if (!ares) {
897 return ldb_module_done(ac->req, NULL, NULL,
898 LDB_ERR_OPERATIONS_ERROR);
900 if (ares->error != LDB_SUCCESS) {
901 return ldb_module_done(ac->req, ares->controls,
902 ares->response, ares->error);
905 if (ares->type != LDB_REPLY_DONE) {
906 talloc_free(ares);
907 return ldb_module_done(ac->req, NULL, NULL,
908 LDB_ERR_OPERATIONS_ERROR);
911 talloc_free(ares);
913 ret = ldb_build_search_req(&search_req, ldb, ac,
914 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
915 "(objectClass=*)",
916 attrs, NULL,
917 ac, get_search_callback,
918 ac->req);
919 if (ret != LDB_SUCCESS) {
920 return ldb_module_done(ac->req, NULL, NULL, ret);
923 ac->step_fn = objectclass_do_mod;
925 ret = ldb_next_request(ac->module, search_req);
926 if (ret != LDB_SUCCESS) {
927 return ldb_module_done(ac->req, NULL, NULL, ret);
929 return LDB_SUCCESS;
932 static int objectclass_do_mod(struct oc_context *ac)
934 struct ldb_context *ldb;
935 const struct dsdb_schema *schema;
936 struct ldb_request *mod_req;
937 char *value;
938 struct ldb_message_element *objectclass_element;
939 struct ldb_message *msg;
940 TALLOC_CTX *mem_ctx;
941 struct class_list *sorted, *current;
942 int ret;
944 ldb = ldb_module_get_ctx(ac->module);
946 if (ac->search_res == NULL) {
947 return LDB_ERR_OPERATIONS_ERROR;
949 schema = dsdb_get_schema(ldb);
951 mem_ctx = talloc_new(ac);
952 if (mem_ctx == NULL) {
953 return LDB_ERR_OPERATIONS_ERROR;
956 /* use a new message structure */
957 msg = ldb_msg_new(ac);
958 if (msg == NULL) {
959 ldb_set_errstring(ldb,
960 "objectclass: could not create new modify msg");
961 talloc_free(mem_ctx);
962 return LDB_ERR_OPERATIONS_ERROR;
965 /* This is now the objectClass list from the database */
966 objectclass_element = ldb_msg_find_element(ac->search_res->message,
967 "objectClass");
968 if (!objectclass_element) {
969 /* Where did it go? bail now... */
970 talloc_free(mem_ctx);
971 return LDB_ERR_OPERATIONS_ERROR;
974 /* modify dn */
975 msg->dn = ac->req->op.mod.message->dn;
977 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
978 if (ret != LDB_SUCCESS) {
979 return ret;
982 /* We must completely replace the existing objectClass entry.
983 * We could do a constrained add/del, but we are meant to be
984 * in a transaction... */
986 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
987 if (ret != LDB_SUCCESS) {
988 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
989 talloc_free(mem_ctx);
990 return ret;
993 /* Move from the linked list back into an ldb msg */
994 for (current = sorted; current; current = current->next) {
995 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
996 if (value == NULL) {
997 ldb_oom(ldb);
998 return LDB_ERR_OPERATIONS_ERROR;
1000 ret = ldb_msg_add_string(msg, "objectClass", value);
1001 if (ret != LDB_SUCCESS) {
1002 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1003 talloc_free(mem_ctx);
1004 return ret;
1008 ret = ldb_msg_sanity_check(ldb, msg);
1009 if (ret != LDB_SUCCESS) {
1010 talloc_free(mem_ctx);
1011 return ret;
1014 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1015 msg,
1016 ac->req->controls,
1017 ac, oc_op_callback,
1018 ac->req);
1019 if (ret != LDB_SUCCESS) {
1020 talloc_free(mem_ctx);
1021 return ret;
1024 talloc_free(mem_ctx);
1025 /* perform the modify */
1026 return ldb_next_request(ac->module, mod_req);
1029 static int objectclass_do_rename(struct oc_context *ac);
1031 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1033 static const char * const attrs[] = { NULL };
1034 struct ldb_context *ldb;
1035 struct ldb_request *search_req;
1036 struct oc_context *ac;
1037 struct ldb_dn *parent_dn;
1038 int ret;
1040 ldb = ldb_module_get_ctx(module);
1042 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1044 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1045 return ldb_next_request(module, req);
1048 /* Firstly ensure we are not trying to rename it to be a child of itself */
1049 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1050 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1051 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1052 ldb_dn_get_linearized(req->op.rename.olddn));
1053 return LDB_ERR_UNWILLING_TO_PERFORM;
1056 ac = oc_init_context(module, req);
1057 if (ac == NULL) {
1058 return LDB_ERR_OPERATIONS_ERROR;
1061 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1062 if (parent_dn == NULL) {
1063 ldb_oom(ldb);
1064 return LDB_ERR_OPERATIONS_ERROR;
1068 it makes a search request, looking for the parent DN to fix up the new DN
1069 to a standard one, at objectclass_do_rename()
1071 ret = ldb_build_search_req(&search_req, ldb,
1072 ac, parent_dn, LDB_SCOPE_BASE,
1073 "(objectClass=*)",
1074 attrs, NULL,
1075 ac, get_search_callback,
1076 req);
1077 if (ret != LDB_SUCCESS) {
1078 return ret;
1081 /* we have to add the show deleted control, as otherwise DRS
1082 deletes will be refused as we will think the target parent
1083 does not exist */
1084 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1086 if (ret != LDB_SUCCESS) {
1087 return ret;
1090 ac->step_fn = objectclass_do_rename;
1092 return ldb_next_request(ac->module, search_req);
1097 static int objectclass_do_rename(struct oc_context *ac)
1099 struct ldb_context *ldb;
1100 struct ldb_request *rename_req;
1101 struct ldb_dn *fixed_dn;
1102 int ret;
1104 ldb = ldb_module_get_ctx(ac->module);
1106 /* Check we have a valid parent */
1107 if (ac->search_res == NULL) {
1108 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1109 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1110 return LDB_ERR_UNWILLING_TO_PERFORM;
1113 /* Fix up the DN to be in the standard form,
1114 * taking particular care to match the parent DN */
1115 ret = fix_dn(ac,
1116 ac->req->op.rename.newdn,
1117 ac->search_res->message->dn,
1118 &fixed_dn);
1119 if (ret != LDB_SUCCESS) {
1120 return ret;
1123 /* TODO: Check this is a valid child to this parent,
1124 * by reading the allowedChildClasses and
1125 * allowedChildClasssesEffective attributes */
1127 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1128 ac->req->op.rename.olddn, fixed_dn,
1129 ac->req->controls,
1130 ac, oc_op_callback,
1131 ac->req);
1132 if (ret != LDB_SUCCESS) {
1133 return ret;
1136 /* perform the rename */
1137 return ldb_next_request(ac->module, rename_req);
1140 static int objectclass_init(struct ldb_module *module)
1142 struct ldb_context *ldb = ldb_module_get_ctx(module);
1143 int ret;
1144 /* Init everything else */
1145 ret = ldb_next_init(module);
1146 if (ret != LDB_SUCCESS) {
1147 return ret;
1150 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1151 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1153 return ldb_next_init(module);
1156 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1157 .name = "objectclass",
1158 .add = objectclass_add,
1159 .modify = objectclass_modify,
1160 .rename = objectclass_rename,
1161 .init_context = objectclass_init