s4:resolve_oids LDB module - not really a change but a nicer method to call "talloc_r...
[Samba/nascimento.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blob910dc92e71bfe637fb9eaa04c37258f92d5b76be
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"
46 #include "util.h"
48 struct oc_context {
50 struct ldb_module *module;
51 struct ldb_request *req;
53 struct ldb_reply *search_res;
55 int (*step_fn)(struct oc_context *);
58 struct class_list {
59 struct class_list *prev, *next;
60 const struct dsdb_class *objectclass;
63 static struct oc_context *oc_init_context(struct ldb_module *module,
64 struct ldb_request *req)
66 struct ldb_context *ldb;
67 struct oc_context *ac;
69 ldb = ldb_module_get_ctx(module);
71 ac = talloc_zero(req, struct oc_context);
72 if (ac == NULL) {
73 ldb_set_errstring(ldb, "Out of Memory");
74 return NULL;
77 ac->module = module;
78 ac->req = req;
80 return ac;
83 static int objectclass_do_add(struct oc_context *ac);
85 /* Sort objectClasses into correct order, and validate that all
86 * objectClasses specified actually exist in the schema
89 static int objectclass_sort(struct ldb_module *module,
90 const struct dsdb_schema *schema,
91 TALLOC_CTX *mem_ctx,
92 struct ldb_message_element *objectclass_element,
93 struct class_list **sorted_out)
95 struct ldb_context *ldb;
96 unsigned int i, lowest;
97 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
99 ldb = ldb_module_get_ctx(module);
101 /* DESIGN:
103 * We work on 4 different 'bins' (implemented here as linked lists):
105 * * sorted: the eventual list, in the order we wish to push
106 * into the database. This is the only ordered list.
108 * * parent_class: The current parent class 'bin' we are
109 * trying to find subclasses for
111 * * subclass: The subclasses we have found so far
113 * * unsorted: The remaining objectClasses
115 * The process is a matter of filtering objectClasses up from
116 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
118 * We start with 'top' (found and promoted to parent_class
119 * initially). Then we find (in unsorted) all the direct
120 * subclasses of 'top'. parent_classes is concatenated onto
121 * the end of 'sorted', and subclass becomes the list in
122 * parent_class.
124 * We then repeat, until we find no more subclasses. Any left
125 * over classes are added to the end.
129 /* Firstly, dump all the objectClass elements into the
130 * unsorted bin, except for 'top', which is special */
131 for (i=0; i < objectclass_element->num_values; i++) {
132 current = talloc(mem_ctx, struct class_list);
133 if (!current) {
134 ldb_oom(ldb);
135 return LDB_ERR_OPERATIONS_ERROR;
137 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
138 if (!current->objectclass) {
139 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
140 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
141 /* This looks weird, but windows apparently returns this for invalid objectClass values */
142 return LDB_ERR_NO_SUCH_ATTRIBUTE;
143 } else if (current->objectclass->isDefunct) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
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;
150 /* Don't add top to list, we will do that later */
151 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
152 DLIST_ADD_END(unsorted, current, struct class_list *);
156 /* Add top here, to prevent duplicates */
157 current = talloc(mem_ctx, struct class_list);
158 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
159 DLIST_ADD_END(sorted, current, struct class_list *);
162 /* For each object: find parent chain */
163 for (current = unsorted; schema && current; current = current->next) {
164 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
165 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
166 break;
169 /* If we didn't get to the end of the list, we need to add this parent */
170 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
171 continue;
174 new_parent = talloc(mem_ctx, struct class_list);
175 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
176 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
181 lowest = UINT_MAX;
182 current_lowest = NULL;
183 for (current = unsorted; schema && current; current = current->next) {
184 if(current->objectclass->subClass_order < lowest) {
185 current_lowest = current;
186 lowest = current->objectclass->subClass_order;
190 if(current_lowest != NULL) {
191 DLIST_REMOVE(unsorted,current_lowest);
192 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
194 } while(unsorted);
197 if (!unsorted) {
198 *sorted_out = sorted;
199 return LDB_SUCCESS;
202 if (!schema) {
203 /* If we don't have schema yet, then just merge the lists again */
204 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
205 *sorted_out = sorted;
206 return LDB_SUCCESS;
209 /* This shouldn't happen, and would break MMC, perhaps there
210 * was no 'top', a conflict in the objectClasses or some other
211 * schema error?
213 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
214 return LDB_ERR_OBJECT_CLASS_VIOLATION;
217 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
219 struct ldb_context *ldb;
220 struct oc_context *ac;
221 int ret;
223 ac = talloc_get_type(req->context, struct oc_context);
224 ldb = ldb_module_get_ctx(ac->module);
226 if (!ares) {
227 return ldb_module_done(ac->req, NULL, NULL,
228 LDB_ERR_OPERATIONS_ERROR);
230 if (ares->error != LDB_SUCCESS &&
231 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
232 return ldb_module_done(ac->req, ares->controls,
233 ares->response, ares->error);
236 ldb_reset_err_string(ldb);
238 switch (ares->type) {
239 case LDB_REPLY_ENTRY:
240 if (ac->search_res != NULL) {
241 ldb_set_errstring(ldb, "Too many results");
242 talloc_free(ares);
243 return ldb_module_done(ac->req, NULL, NULL,
244 LDB_ERR_OPERATIONS_ERROR);
247 ac->search_res = talloc_steal(ac, ares);
248 break;
250 case LDB_REPLY_REFERRAL:
251 /* ignore */
252 talloc_free(ares);
253 break;
255 case LDB_REPLY_DONE:
256 talloc_free(ares);
257 ret = ac->step_fn(ac);
258 if (ret != LDB_SUCCESS) {
259 return ldb_module_done(ac->req, NULL, NULL, ret);
261 break;
264 return LDB_SUCCESS;
267 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
269 struct oc_context *ac;
271 ac = talloc_get_type(req->context, struct oc_context);
273 if (!ares) {
274 return ldb_module_done(ac->req, NULL, NULL,
275 LDB_ERR_OPERATIONS_ERROR);
277 if (ares->error != LDB_SUCCESS) {
278 return ldb_module_done(ac->req, ares->controls,
279 ares->response, ares->error);
282 if (ares->type != LDB_REPLY_DONE) {
283 talloc_free(ares);
284 return ldb_module_done(ac->req, NULL, NULL,
285 LDB_ERR_OPERATIONS_ERROR);
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
294 This should mean that if the parent is:
295 CN=Users,DC=samba,DC=example,DC=com
296 and a proposed child is
297 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
299 The resulting DN should be:
301 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
304 static int fix_dn(TALLOC_CTX *mem_ctx,
305 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
306 struct ldb_dn **fixed_dn)
308 char *upper_rdn_attr;
309 const struct ldb_val *rdn_val;
311 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
312 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
314 /* We need the attribute name in upper case */
315 upper_rdn_attr = strupper_talloc(*fixed_dn,
316 ldb_dn_get_rdn_name(newdn));
317 if (!upper_rdn_attr) {
318 return LDB_ERR_OPERATIONS_ERROR;
321 /* Create a new child */
322 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
323 return LDB_ERR_OPERATIONS_ERROR;
327 rdn_val = ldb_dn_get_rdn_val(newdn);
329 #if 0
330 /* the rules for rDN length constraints are more complex than
331 this. Until we understand them we need to leave this
332 constraint out. Otherwise we break replication, as windows
333 does sometimes send us rDNs longer than 64 */
334 if (!rdn_val || rdn_val->length > 64) {
335 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
337 #endif
340 /* And replace it with CN=foo (we need the attribute in upper case */
341 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
344 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
345 static int fix_check_attributes(struct ldb_context *ldb,
346 const struct dsdb_schema *schema,
347 struct ldb_message *msg,
348 enum ldb_request_type op)
350 unsigned int i;
351 for (i=0; i < msg->num_elements; i++) {
352 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
353 /* Add in a very special case for 'clearTextPassword',
354 * which is used for internal processing only, and is
355 * not presented in the schema */
356 if (!attribute) {
357 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
358 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
359 /* Apparently Windows sends exactly this behaviour */
360 return LDB_ERR_NO_SUCH_ATTRIBUTE;
362 } else {
363 msg->elements[i].name = attribute->lDAPDisplayName;
365 /* We have to deny write operations on constructed attributes */
366 if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
367 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
368 if (op == LDB_ADD) {
369 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
370 } else {
371 return LDB_ERR_CONSTRAINT_VIOLATION;
378 return LDB_SUCCESS;
381 static int objectclass_do_add(struct oc_context *ac);
383 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
385 struct ldb_context *ldb;
386 struct ldb_request *search_req;
387 struct oc_context *ac;
388 struct ldb_dn *parent_dn;
389 int ret;
390 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
392 ldb = ldb_module_get_ctx(module);
394 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
396 /* do not manipulate our control entries */
397 if (ldb_dn_is_special(req->op.add.message->dn)) {
398 return ldb_next_request(module, req);
401 /* the objectClass must be specified on add */
402 if (ldb_msg_find_element(req->op.add.message,
403 "objectClass") == NULL) {
404 return LDB_ERR_OBJECT_CLASS_VIOLATION;
407 ac = oc_init_context(module, req);
408 if (ac == NULL) {
409 return LDB_ERR_OPERATIONS_ERROR;
412 /* If there isn't a parent, just go on to the add processing */
413 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
414 return objectclass_do_add(ac);
417 /* get copy of parent DN */
418 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
419 if (parent_dn == NULL) {
420 ldb_oom(ldb);
421 return LDB_ERR_OPERATIONS_ERROR;
424 ret = ldb_build_search_req(&search_req, ldb,
425 ac, parent_dn, LDB_SCOPE_BASE,
426 "(objectClass=*)", parent_attrs,
427 NULL,
428 ac, get_search_callback,
429 req);
430 if (ret != LDB_SUCCESS) {
431 return ret;
433 talloc_steal(search_req, parent_dn);
435 ac->step_fn = objectclass_do_add;
437 return ldb_next_request(ac->module, search_req);
440 static int objectclass_do_add(struct oc_context *ac)
442 struct ldb_context *ldb;
443 const struct dsdb_schema *schema;
444 struct ldb_request *add_req;
445 char *value;
446 struct ldb_message_element *objectclass_element, *el;
447 struct ldb_message *msg;
448 TALLOC_CTX *mem_ctx;
449 struct class_list *sorted, *current;
450 int ret;
451 const struct dsdb_class *objectclass;
452 int32_t systemFlags = 0;
453 const char *rdn_name = NULL;
455 ldb = ldb_module_get_ctx(ac->module);
456 schema = dsdb_get_schema(ldb, ac);
458 mem_ctx = talloc_new(ac);
459 if (mem_ctx == NULL) {
460 ldb_oom(ldb);
461 return LDB_ERR_OPERATIONS_ERROR;
464 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
466 /* Check we have a valid parent */
467 if (ac->search_res == NULL) {
468 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
469 msg->dn) == 0) {
470 /* Allow the tree to be started */
472 /* but don't keep any error string, it's meaningless */
473 ldb_set_errstring(ldb, NULL);
474 } else {
475 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
476 ldb_dn_get_linearized(msg->dn));
477 talloc_free(mem_ctx);
478 return LDB_ERR_NO_SUCH_OBJECT;
480 } else {
482 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
483 ret = fix_dn(msg,
484 ac->req->op.add.message->dn,
485 ac->search_res->message->dn,
486 &msg->dn);
488 if (ret != LDB_SUCCESS) {
489 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
490 ldb_dn_get_linearized(ac->req->op.add.message->dn));
491 talloc_free(mem_ctx);
492 return ret;
496 if (schema) {
497 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
498 if (ret != LDB_SUCCESS) {
499 talloc_free(mem_ctx);
500 return ret;
503 /* This is now the objectClass list from the database */
504 objectclass_element = ldb_msg_find_element(msg, "objectClass");
506 if (!objectclass_element) {
507 /* Where did it go? bail now... */
508 talloc_free(mem_ctx);
509 return LDB_ERR_OPERATIONS_ERROR;
511 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
512 if (ret != LDB_SUCCESS) {
513 talloc_free(mem_ctx);
514 return ret;
517 ldb_msg_remove_attr(msg, "objectClass");
518 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
520 if (ret != LDB_SUCCESS) {
521 talloc_free(mem_ctx);
522 return ret;
525 /* We must completely replace the existing objectClass entry,
526 * because we need it sorted */
528 /* Move from the linked list back into an ldb msg */
529 for (current = sorted; current; current = current->next) {
530 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
531 if (value == NULL) {
532 ldb_oom(ldb);
533 talloc_free(mem_ctx);
534 return LDB_ERR_OPERATIONS_ERROR;
536 ret = ldb_msg_add_string(msg, "objectClass", value);
537 if (ret != LDB_SUCCESS) {
538 ldb_set_errstring(ldb,
539 "objectclass: could not re-add sorted "
540 "objectclass to modify msg");
541 talloc_free(mem_ctx);
542 return ret;
546 /* Retrive the message again so get_last_structural_class works */
547 objectclass_element = ldb_msg_find_element(msg, "objectClass");
549 /* Make sure its valid to add an object of this type */
550 objectclass = get_last_structural_class(schema,objectclass_element);
551 if(objectclass == NULL) {
552 ldb_asprintf_errstring(ldb,
553 "Failed to find a structural class for %s",
554 ldb_dn_get_linearized(msg->dn));
555 return LDB_ERR_NAMING_VIOLATION;
558 rdn_name = ldb_dn_get_rdn_name(msg->dn);
559 if (objectclass->rDNAttID
560 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
561 ldb_asprintf_errstring(ldb,
562 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
563 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
564 return LDB_ERR_NAMING_VIOLATION;
567 if (ac->search_res && ac->search_res->message) {
568 struct ldb_message_element *oc_el
569 = ldb_msg_find_element(ac->search_res->message, "objectClass");
571 bool allowed_class = false;
572 int i, j;
573 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
574 const struct dsdb_class *sclass;
576 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
577 if (!sclass) {
578 /* We don't know this class? what is going on? */
579 continue;
581 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
582 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
583 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
584 allowed_class = true;
585 break;
588 } else {
589 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
590 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
591 allowed_class = true;
592 break;
598 if (!allowed_class) {
599 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
600 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
601 return LDB_ERR_NAMING_VIOLATION;
605 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
606 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
607 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
608 return LDB_ERR_UNWILLING_TO_PERFORM;
611 if (!ldb_msg_find_element(msg, "objectCategory")) {
612 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
613 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
614 /* Strip off extended components */
615 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
616 value = ldb_dn_alloc_linearized(msg, dn);
617 talloc_free(dn);
618 } else {
619 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
621 if (value == NULL) {
622 ldb_oom(ldb);
623 talloc_free(mem_ctx);
624 return LDB_ERR_OPERATIONS_ERROR;
626 ldb_msg_add_string(msg, "objectCategory", value);
628 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
629 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
630 "TRUE");
633 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
634 el = ldb_msg_find_element(msg, "systemFlags");
636 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
638 if (el) {
639 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
640 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
641 ldb_msg_remove_element(msg, el);
644 /* This flag is only allowed on attributeSchema objects */
645 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
646 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
649 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
650 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
651 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
652 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
653 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
654 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
656 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
657 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
658 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
659 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
662 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
664 if (el || systemFlags != 0) {
665 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
669 talloc_free(mem_ctx);
670 ret = ldb_msg_sanity_check(ldb, msg);
673 if (ret != LDB_SUCCESS) {
674 return ret;
677 ret = ldb_build_add_req(&add_req, ldb, ac,
678 msg,
679 ac->req->controls,
680 ac, oc_op_callback,
681 ac->req);
682 if (ret != LDB_SUCCESS) {
683 return ret;
686 /* perform the add */
687 return ldb_next_request(ac->module, add_req);
690 static int oc_modify_callback(struct ldb_request *req,
691 struct ldb_reply *ares);
692 static int objectclass_do_mod(struct oc_context *ac);
694 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
696 struct ldb_context *ldb = ldb_module_get_ctx(module);
697 struct ldb_message_element *objectclass_element;
698 struct ldb_message *msg;
699 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
700 struct class_list *sorted, *current;
701 struct ldb_request *down_req;
702 struct oc_context *ac;
703 TALLOC_CTX *mem_ctx;
704 char *value;
705 int ret;
707 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
709 /* do not manipulate our control entries */
710 if (ldb_dn_is_special(req->op.mod.message->dn)) {
711 return ldb_next_request(module, req);
714 /* Without schema, there isn't much to do here */
715 if (!schema) {
716 return ldb_next_request(module, req);
719 /* As with the "real" AD we don't accept empty messages */
720 if (req->op.mod.message->num_elements == 0) {
721 ldb_set_errstring(ldb, "objectclass: modify message must have "
722 "elements/attributes!");
723 return LDB_ERR_UNWILLING_TO_PERFORM;
726 ac = oc_init_context(module, req);
727 if (ac == NULL) {
728 ldb_oom(ldb);
729 return LDB_ERR_OPERATIONS_ERROR;
732 if (!talloc_reference(ac, schema)) {
733 ldb_oom(ldb);
734 return LDB_ERR_OPERATIONS_ERROR;
737 /* If no part of this touches the objectClass, then we don't
738 * need to make any changes. */
739 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
741 /* If the only operation is the deletion of the objectClass
742 * then go on with just fixing the attribute case */
743 if (!objectclass_element) {
744 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
745 if (msg == NULL) {
746 return LDB_ERR_OPERATIONS_ERROR;
749 ret = fix_check_attributes(ldb, schema, msg, req->operation);
750 if (ret != LDB_SUCCESS) {
751 return ret;
754 ret = ldb_build_mod_req(&down_req, ldb, ac,
755 msg,
756 req->controls,
757 ac, oc_op_callback,
758 req);
759 if (ret != LDB_SUCCESS) {
760 return ret;
763 /* go on with the call chain */
764 return ldb_next_request(module, down_req);
767 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
768 case LDB_FLAG_MOD_DELETE:
769 if (objectclass_element->num_values == 0) {
770 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
772 break;
774 case LDB_FLAG_MOD_REPLACE:
775 mem_ctx = talloc_new(ac);
776 if (mem_ctx == NULL) {
777 return LDB_ERR_OPERATIONS_ERROR;
780 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
781 if (msg == NULL) {
782 talloc_free(mem_ctx);
783 return LDB_ERR_OPERATIONS_ERROR;
786 ret = fix_check_attributes(ldb, schema, msg, req->operation);
787 if (ret != LDB_SUCCESS) {
788 talloc_free(mem_ctx);
789 return ret;
792 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
793 if (ret != LDB_SUCCESS) {
794 talloc_free(mem_ctx);
795 return ret;
798 /* We must completely replace the existing objectClass entry,
799 * because we need it sorted */
801 ldb_msg_remove_attr(msg, "objectClass");
802 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
804 if (ret != LDB_SUCCESS) {
805 talloc_free(mem_ctx);
806 return ret;
809 /* Move from the linked list back into an ldb msg */
810 for (current = sorted; current; current = current->next) {
811 /* copy the value as this string is on the schema
812 * context and we can't rely on it not changing
813 * before the operation is over */
814 value = talloc_strdup(msg,
815 current->objectclass->lDAPDisplayName);
816 if (value == NULL) {
817 ldb_oom(ldb);
818 talloc_free(mem_ctx);
819 return LDB_ERR_OPERATIONS_ERROR;
821 ret = ldb_msg_add_string(msg, "objectClass", value);
822 if (ret != LDB_SUCCESS) {
823 ldb_set_errstring(ldb,
824 "objectclass: could not re-add sorted "
825 "objectclass to modify msg");
826 talloc_free(mem_ctx);
827 return ret;
831 talloc_free(mem_ctx);
833 ret = ldb_msg_sanity_check(ldb, msg);
834 if (ret != LDB_SUCCESS) {
835 return ret;
838 ret = ldb_build_mod_req(&down_req, ldb, ac,
839 msg,
840 req->controls,
841 ac, oc_op_callback,
842 req);
843 if (ret != LDB_SUCCESS) {
844 return ret;
847 /* go on with the call chain */
848 return ldb_next_request(module, down_req);
851 /* This isn't the default branch of the switch, but a 'in any
852 * other case'. When a delete isn't for all objectClasses for
853 * example
856 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
857 if (msg == NULL) {
858 ldb_oom(ldb);
859 return LDB_ERR_OPERATIONS_ERROR;
862 ret = fix_check_attributes(ldb, schema, msg, req->operation);
863 if (ret != LDB_SUCCESS) {
864 ldb_oom(ldb);
865 return ret;
868 ret = ldb_build_mod_req(&down_req, ldb, ac,
869 msg,
870 req->controls,
871 ac, oc_modify_callback,
872 req);
873 if (ret != LDB_SUCCESS) {
874 return ret;
877 return ldb_next_request(module, down_req);
880 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
882 struct ldb_context *ldb;
883 static const char * const attrs[] = { "objectClass", NULL };
884 struct ldb_request *search_req;
885 struct oc_context *ac;
886 int ret;
888 ac = talloc_get_type(req->context, struct oc_context);
889 ldb = ldb_module_get_ctx(ac->module);
891 if (!ares) {
892 return ldb_module_done(ac->req, NULL, NULL,
893 LDB_ERR_OPERATIONS_ERROR);
895 if (ares->error != LDB_SUCCESS) {
896 return ldb_module_done(ac->req, ares->controls,
897 ares->response, ares->error);
900 if (ares->type != LDB_REPLY_DONE) {
901 talloc_free(ares);
902 return ldb_module_done(ac->req, NULL, NULL,
903 LDB_ERR_OPERATIONS_ERROR);
906 talloc_free(ares);
908 ret = ldb_build_search_req(&search_req, ldb, ac,
909 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
910 "(objectClass=*)",
911 attrs, NULL,
912 ac, get_search_callback,
913 ac->req);
914 if (ret != LDB_SUCCESS) {
915 return ldb_module_done(ac->req, NULL, NULL, ret);
918 ac->step_fn = objectclass_do_mod;
920 ret = ldb_next_request(ac->module, search_req);
921 if (ret != LDB_SUCCESS) {
922 return ldb_module_done(ac->req, NULL, NULL, ret);
924 return LDB_SUCCESS;
927 static int objectclass_do_mod(struct oc_context *ac)
929 struct ldb_context *ldb;
930 const struct dsdb_schema *schema;
931 struct ldb_request *mod_req;
932 char *value;
933 struct ldb_message_element *objectclass_element;
934 struct ldb_message *msg;
935 TALLOC_CTX *mem_ctx;
936 struct class_list *sorted, *current;
937 int ret;
939 ldb = ldb_module_get_ctx(ac->module);
941 if (ac->search_res == NULL) {
942 return LDB_ERR_OPERATIONS_ERROR;
944 schema = dsdb_get_schema(ldb, ac);
946 mem_ctx = talloc_new(ac);
947 if (mem_ctx == NULL) {
948 return LDB_ERR_OPERATIONS_ERROR;
951 /* use a new message structure */
952 msg = ldb_msg_new(ac);
953 if (msg == NULL) {
954 ldb_set_errstring(ldb,
955 "objectclass: could not create new modify msg");
956 talloc_free(mem_ctx);
957 return LDB_ERR_OPERATIONS_ERROR;
960 /* This is now the objectClass list from the database */
961 objectclass_element = ldb_msg_find_element(ac->search_res->message,
962 "objectClass");
963 if (!objectclass_element) {
964 /* Where did it go? bail now... */
965 talloc_free(mem_ctx);
966 return LDB_ERR_OPERATIONS_ERROR;
969 /* modify dn */
970 msg->dn = ac->req->op.mod.message->dn;
972 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
973 if (ret != LDB_SUCCESS) {
974 return ret;
977 /* We must completely replace the existing objectClass entry.
978 * We could do a constrained add/del, but we are meant to be
979 * in a transaction... */
981 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
982 if (ret != LDB_SUCCESS) {
983 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
984 talloc_free(mem_ctx);
985 return ret;
988 /* Move from the linked list back into an ldb msg */
989 for (current = sorted; current; current = current->next) {
990 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
991 if (value == NULL) {
992 ldb_oom(ldb);
993 return LDB_ERR_OPERATIONS_ERROR;
995 ret = ldb_msg_add_string(msg, "objectClass", value);
996 if (ret != LDB_SUCCESS) {
997 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
998 talloc_free(mem_ctx);
999 return ret;
1003 ret = ldb_msg_sanity_check(ldb, msg);
1004 if (ret != LDB_SUCCESS) {
1005 talloc_free(mem_ctx);
1006 return ret;
1009 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1010 msg,
1011 ac->req->controls,
1012 ac, oc_op_callback,
1013 ac->req);
1014 if (ret != LDB_SUCCESS) {
1015 talloc_free(mem_ctx);
1016 return ret;
1019 talloc_free(mem_ctx);
1020 /* perform the modify */
1021 return ldb_next_request(ac->module, mod_req);
1024 static int objectclass_do_rename(struct oc_context *ac);
1026 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1028 static const char * const attrs[] = { NULL };
1029 struct ldb_context *ldb;
1030 struct ldb_request *search_req;
1031 struct oc_context *ac;
1032 struct ldb_dn *parent_dn;
1033 int ret;
1035 ldb = ldb_module_get_ctx(module);
1037 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1039 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1040 return ldb_next_request(module, req);
1043 /* Firstly ensure we are not trying to rename it to be a child of itself */
1044 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1045 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1046 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1047 ldb_dn_get_linearized(req->op.rename.olddn));
1048 return LDB_ERR_UNWILLING_TO_PERFORM;
1051 ac = oc_init_context(module, req);
1052 if (ac == NULL) {
1053 return LDB_ERR_OPERATIONS_ERROR;
1056 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1057 if (parent_dn == NULL) {
1058 ldb_oom(ldb);
1059 return LDB_ERR_OPERATIONS_ERROR;
1063 it makes a search request, looking for the parent DN to fix up the new DN
1064 to a standard one, at objectclass_do_rename()
1066 ret = ldb_build_search_req(&search_req, ldb,
1067 ac, parent_dn, LDB_SCOPE_BASE,
1068 "(objectClass=*)",
1069 attrs, NULL,
1070 ac, get_search_callback,
1071 req);
1072 if (ret != LDB_SUCCESS) {
1073 return ret;
1076 /* we have to add the show deleted control, as otherwise DRS
1077 deletes will be refused as we will think the target parent
1078 does not exist */
1079 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1081 if (ret != LDB_SUCCESS) {
1082 return ret;
1085 ac->step_fn = objectclass_do_rename;
1087 return ldb_next_request(ac->module, search_req);
1092 static int objectclass_do_rename(struct oc_context *ac)
1094 struct ldb_context *ldb;
1095 struct ldb_request *rename_req;
1096 struct ldb_dn *fixed_dn;
1097 int ret;
1099 ldb = ldb_module_get_ctx(ac->module);
1101 /* Check we have a valid parent */
1102 if (ac->search_res == NULL) {
1103 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1104 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1105 return LDB_ERR_UNWILLING_TO_PERFORM;
1108 /* Fix up the DN to be in the standard form,
1109 * taking particular care to match the parent DN */
1110 ret = fix_dn(ac,
1111 ac->req->op.rename.newdn,
1112 ac->search_res->message->dn,
1113 &fixed_dn);
1114 if (ret != LDB_SUCCESS) {
1115 return ret;
1118 /* TODO: Check this is a valid child to this parent,
1119 * by reading the allowedChildClasses and
1120 * allowedChildClasssesEffective attributes */
1122 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1123 ac->req->op.rename.olddn, fixed_dn,
1124 ac->req->controls,
1125 ac, oc_op_callback,
1126 ac->req);
1127 if (ret != LDB_SUCCESS) {
1128 return ret;
1131 /* perform the rename */
1132 return ldb_next_request(ac->module, rename_req);
1135 static int objectclass_init(struct ldb_module *module)
1137 struct ldb_context *ldb = ldb_module_get_ctx(module);
1138 int ret;
1139 /* Init everything else */
1140 ret = ldb_next_init(module);
1141 if (ret != LDB_SUCCESS) {
1142 return ret;
1145 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1146 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1148 return ret;
1151 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1152 .name = "objectclass",
1153 .add = objectclass_add,
1154 .modify = objectclass_modify,
1155 .rename = objectclass_rename,
1156 .init_context = objectclass_init