s4:objectclass LDB module - change counter variabls to "unsigned" where appropriate
[Samba/cd1.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blobd5e28d3152e50434d17153d59b77644a00ecd994
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);
458 mem_ctx = talloc_new(ac);
459 if (mem_ctx == NULL) {
460 return LDB_ERR_OPERATIONS_ERROR;
463 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
465 /* Check we have a valid parent */
466 if (ac->search_res == NULL) {
467 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
468 msg->dn) == 0) {
469 /* Allow the tree to be started */
471 /* but don't keep any error string, it's meaningless */
472 ldb_set_errstring(ldb, NULL);
473 } else {
474 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
475 ldb_dn_get_linearized(msg->dn));
476 talloc_free(mem_ctx);
477 return LDB_ERR_NO_SUCH_OBJECT;
479 } else {
481 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
482 ret = fix_dn(msg,
483 ac->req->op.add.message->dn,
484 ac->search_res->message->dn,
485 &msg->dn);
487 if (ret != LDB_SUCCESS) {
488 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form",
489 ldb_dn_get_linearized(ac->req->op.add.message->dn));
490 talloc_free(mem_ctx);
491 return ret;
495 if (schema) {
496 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
497 if (ret != LDB_SUCCESS) {
498 talloc_free(mem_ctx);
499 return ret;
502 /* This is now the objectClass list from the database */
503 objectclass_element = ldb_msg_find_element(msg, "objectClass");
505 if (!objectclass_element) {
506 /* Where did it go? bail now... */
507 talloc_free(mem_ctx);
508 return LDB_ERR_OPERATIONS_ERROR;
510 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
511 if (ret != LDB_SUCCESS) {
512 talloc_free(mem_ctx);
513 return ret;
516 ldb_msg_remove_attr(msg, "objectClass");
517 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
519 if (ret != LDB_SUCCESS) {
520 talloc_free(mem_ctx);
521 return ret;
524 /* We must completely replace the existing objectClass entry,
525 * because we need it sorted */
527 /* Move from the linked list back into an ldb msg */
528 for (current = sorted; current; current = current->next) {
529 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
530 if (value == NULL) {
531 ldb_oom(ldb);
532 talloc_free(mem_ctx);
533 return LDB_ERR_OPERATIONS_ERROR;
535 ret = ldb_msg_add_string(msg, "objectClass", value);
536 if (ret != LDB_SUCCESS) {
537 ldb_set_errstring(ldb,
538 "objectclass: could not re-add sorted "
539 "objectclass to modify msg");
540 talloc_free(mem_ctx);
541 return ret;
545 /* Retrive the message again so get_last_structural_class works */
546 objectclass_element = ldb_msg_find_element(msg, "objectClass");
548 /* Make sure its valid to add an object of this type */
549 objectclass = get_last_structural_class(schema,objectclass_element);
550 if(objectclass == NULL) {
551 ldb_asprintf_errstring(ldb,
552 "Failed to find a structural class for %s",
553 ldb_dn_get_linearized(msg->dn));
554 return LDB_ERR_NAMING_VIOLATION;
557 rdn_name = ldb_dn_get_rdn_name(msg->dn);
558 if (objectclass->rDNAttID
559 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
560 ldb_asprintf_errstring(ldb,
561 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
562 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
563 return LDB_ERR_NAMING_VIOLATION;
566 if (ac->search_res && ac->search_res->message) {
567 struct ldb_message_element *oc_el
568 = ldb_msg_find_element(ac->search_res->message, "objectClass");
570 bool allowed_class = false;
571 int i, j;
572 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
573 const struct dsdb_class *sclass;
575 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
576 if (!sclass) {
577 /* We don't know this class? what is going on? */
578 continue;
580 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
581 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
582 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
583 allowed_class = true;
584 break;
587 } else {
588 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
589 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
590 allowed_class = true;
591 break;
597 if (!allowed_class) {
598 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
599 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
600 return LDB_ERR_NAMING_VIOLATION;
604 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
605 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
606 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
607 return LDB_ERR_UNWILLING_TO_PERFORM;
610 if (!ldb_msg_find_element(msg, "objectCategory")) {
611 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
612 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
613 /* Strip off extended components */
614 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
615 value = ldb_dn_alloc_linearized(msg, dn);
616 talloc_free(dn);
617 } else {
618 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
620 if (value == NULL) {
621 ldb_oom(ldb);
622 talloc_free(mem_ctx);
623 return LDB_ERR_OPERATIONS_ERROR;
625 ldb_msg_add_string(msg, "objectCategory", value);
627 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
628 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
629 "TRUE");
632 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
633 el = ldb_msg_find_element(msg, "systemFlags");
635 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
637 if (el) {
638 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
639 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
640 ldb_msg_remove_element(msg, el);
643 /* This flag is only allowed on attributeSchema objects */
644 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
645 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
648 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
649 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
650 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
651 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
652 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
653 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
655 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
656 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
657 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
658 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
661 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
663 if (el || systemFlags != 0) {
664 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
668 talloc_free(mem_ctx);
669 ret = ldb_msg_sanity_check(ldb, msg);
672 if (ret != LDB_SUCCESS) {
673 return ret;
676 ret = ldb_build_add_req(&add_req, ldb, ac,
677 msg,
678 ac->req->controls,
679 ac, oc_op_callback,
680 ac->req);
681 if (ret != LDB_SUCCESS) {
682 return ret;
685 /* perform the add */
686 return ldb_next_request(ac->module, add_req);
689 static int oc_modify_callback(struct ldb_request *req,
690 struct ldb_reply *ares);
691 static int objectclass_do_mod(struct oc_context *ac);
693 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
695 struct ldb_context *ldb = ldb_module_get_ctx(module);
696 struct ldb_message_element *objectclass_element;
697 struct ldb_message *msg;
698 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
699 struct class_list *sorted, *current;
700 struct ldb_request *down_req;
701 struct oc_context *ac;
702 TALLOC_CTX *mem_ctx;
703 char *value;
704 int ret;
706 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
708 /* do not manipulate our control entries */
709 if (ldb_dn_is_special(req->op.mod.message->dn)) {
710 return ldb_next_request(module, req);
713 /* Without schema, there isn't much to do here */
714 if (!schema) {
715 return ldb_next_request(module, req);
718 /* As with the "real" AD we don't accept empty messages */
719 if (req->op.mod.message->num_elements == 0) {
720 ldb_set_errstring(ldb, "objectclass: modify message must have "
721 "elements/attributes!");
722 return LDB_ERR_UNWILLING_TO_PERFORM;
725 ac = oc_init_context(module, req);
726 if (ac == NULL) {
727 return LDB_ERR_OPERATIONS_ERROR;
730 /* If no part of this touches the objectClass, then we don't
731 * need to make any changes. */
732 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
734 /* If the only operation is the deletion of the objectClass
735 * then go on with just fixing the attribute case */
736 if (!objectclass_element) {
737 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
738 if (msg == NULL) {
739 return LDB_ERR_OPERATIONS_ERROR;
742 ret = fix_check_attributes(ldb, schema, msg, req->operation);
743 if (ret != LDB_SUCCESS) {
744 return ret;
747 ret = ldb_build_mod_req(&down_req, ldb, ac,
748 msg,
749 req->controls,
750 ac, oc_op_callback,
751 req);
752 if (ret != LDB_SUCCESS) {
753 return ret;
756 /* go on with the call chain */
757 return ldb_next_request(module, down_req);
760 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
761 case LDB_FLAG_MOD_DELETE:
762 if (objectclass_element->num_values == 0) {
763 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
765 break;
767 case LDB_FLAG_MOD_REPLACE:
768 mem_ctx = talloc_new(ac);
769 if (mem_ctx == NULL) {
770 return LDB_ERR_OPERATIONS_ERROR;
773 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
774 if (msg == NULL) {
775 talloc_free(mem_ctx);
776 return LDB_ERR_OPERATIONS_ERROR;
779 ret = fix_check_attributes(ldb, schema, msg, req->operation);
780 if (ret != LDB_SUCCESS) {
781 talloc_free(mem_ctx);
782 return ret;
785 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
786 if (ret != LDB_SUCCESS) {
787 talloc_free(mem_ctx);
788 return ret;
791 /* We must completely replace the existing objectClass entry,
792 * because we need it sorted */
794 ldb_msg_remove_attr(msg, "objectClass");
795 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
797 if (ret != LDB_SUCCESS) {
798 talloc_free(mem_ctx);
799 return ret;
802 /* Move from the linked list back into an ldb msg */
803 for (current = sorted; current; current = current->next) {
804 /* copy the value as this string is on the schema
805 * context and we can't rely on it not changing
806 * before the operation is over */
807 value = talloc_strdup(msg,
808 current->objectclass->lDAPDisplayName);
809 if (value == NULL) {
810 ldb_oom(ldb);
811 talloc_free(mem_ctx);
812 return LDB_ERR_OPERATIONS_ERROR;
814 ret = ldb_msg_add_string(msg, "objectClass", value);
815 if (ret != LDB_SUCCESS) {
816 ldb_set_errstring(ldb,
817 "objectclass: could not re-add sorted "
818 "objectclass to modify msg");
819 talloc_free(mem_ctx);
820 return ret;
824 talloc_free(mem_ctx);
826 ret = ldb_msg_sanity_check(ldb, msg);
827 if (ret != LDB_SUCCESS) {
828 return ret;
831 ret = ldb_build_mod_req(&down_req, ldb, ac,
832 msg,
833 req->controls,
834 ac, oc_op_callback,
835 req);
836 if (ret != LDB_SUCCESS) {
837 return ret;
840 /* go on with the call chain */
841 return ldb_next_request(module, down_req);
844 /* This isn't the default branch of the switch, but a 'in any
845 * other case'. When a delete isn't for all objectClasses for
846 * example
849 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
850 if (msg == NULL) {
851 ldb_oom(ldb);
852 return LDB_ERR_OPERATIONS_ERROR;
855 ret = fix_check_attributes(ldb, schema, msg, req->operation);
856 if (ret != LDB_SUCCESS) {
857 ldb_oom(ldb);
858 return ret;
861 ret = ldb_build_mod_req(&down_req, ldb, ac,
862 msg,
863 req->controls,
864 ac, oc_modify_callback,
865 req);
866 if (ret != LDB_SUCCESS) {
867 return ret;
870 return ldb_next_request(module, down_req);
873 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
875 struct ldb_context *ldb;
876 static const char * const attrs[] = { "objectClass", NULL };
877 struct ldb_request *search_req;
878 struct oc_context *ac;
879 int ret;
881 ac = talloc_get_type(req->context, struct oc_context);
882 ldb = ldb_module_get_ctx(ac->module);
884 if (!ares) {
885 return ldb_module_done(ac->req, NULL, NULL,
886 LDB_ERR_OPERATIONS_ERROR);
888 if (ares->error != LDB_SUCCESS) {
889 return ldb_module_done(ac->req, ares->controls,
890 ares->response, ares->error);
893 if (ares->type != LDB_REPLY_DONE) {
894 talloc_free(ares);
895 return ldb_module_done(ac->req, NULL, NULL,
896 LDB_ERR_OPERATIONS_ERROR);
899 talloc_free(ares);
901 ret = ldb_build_search_req(&search_req, ldb, ac,
902 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
903 "(objectClass=*)",
904 attrs, NULL,
905 ac, get_search_callback,
906 ac->req);
907 if (ret != LDB_SUCCESS) {
908 return ldb_module_done(ac->req, NULL, NULL, ret);
911 ac->step_fn = objectclass_do_mod;
913 ret = ldb_next_request(ac->module, search_req);
914 if (ret != LDB_SUCCESS) {
915 return ldb_module_done(ac->req, NULL, NULL, ret);
917 return LDB_SUCCESS;
920 static int objectclass_do_mod(struct oc_context *ac)
922 struct ldb_context *ldb;
923 const struct dsdb_schema *schema;
924 struct ldb_request *mod_req;
925 char *value;
926 struct ldb_message_element *objectclass_element;
927 struct ldb_message *msg;
928 TALLOC_CTX *mem_ctx;
929 struct class_list *sorted, *current;
930 int ret;
932 ldb = ldb_module_get_ctx(ac->module);
934 if (ac->search_res == NULL) {
935 return LDB_ERR_OPERATIONS_ERROR;
937 schema = dsdb_get_schema(ldb);
939 mem_ctx = talloc_new(ac);
940 if (mem_ctx == NULL) {
941 return LDB_ERR_OPERATIONS_ERROR;
944 /* use a new message structure */
945 msg = ldb_msg_new(ac);
946 if (msg == NULL) {
947 ldb_set_errstring(ldb,
948 "objectclass: could not create new modify msg");
949 talloc_free(mem_ctx);
950 return LDB_ERR_OPERATIONS_ERROR;
953 /* This is now the objectClass list from the database */
954 objectclass_element = ldb_msg_find_element(ac->search_res->message,
955 "objectClass");
956 if (!objectclass_element) {
957 /* Where did it go? bail now... */
958 talloc_free(mem_ctx);
959 return LDB_ERR_OPERATIONS_ERROR;
962 /* modify dn */
963 msg->dn = ac->req->op.mod.message->dn;
965 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
966 if (ret != LDB_SUCCESS) {
967 return ret;
970 /* We must completely replace the existing objectClass entry.
971 * We could do a constrained add/del, but we are meant to be
972 * in a transaction... */
974 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
975 if (ret != LDB_SUCCESS) {
976 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
977 talloc_free(mem_ctx);
978 return ret;
981 /* Move from the linked list back into an ldb msg */
982 for (current = sorted; current; current = current->next) {
983 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
984 if (value == NULL) {
985 ldb_oom(ldb);
986 return LDB_ERR_OPERATIONS_ERROR;
988 ret = ldb_msg_add_string(msg, "objectClass", value);
989 if (ret != LDB_SUCCESS) {
990 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
991 talloc_free(mem_ctx);
992 return ret;
996 ret = ldb_msg_sanity_check(ldb, msg);
997 if (ret != LDB_SUCCESS) {
998 talloc_free(mem_ctx);
999 return ret;
1002 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1003 msg,
1004 ac->req->controls,
1005 ac, oc_op_callback,
1006 ac->req);
1007 if (ret != LDB_SUCCESS) {
1008 talloc_free(mem_ctx);
1009 return ret;
1012 talloc_free(mem_ctx);
1013 /* perform the modify */
1014 return ldb_next_request(ac->module, mod_req);
1017 static int objectclass_do_rename(struct oc_context *ac);
1019 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1021 static const char * const attrs[] = { NULL };
1022 struct ldb_context *ldb;
1023 struct ldb_request *search_req;
1024 struct oc_context *ac;
1025 struct ldb_dn *parent_dn;
1026 int ret;
1028 ldb = ldb_module_get_ctx(module);
1030 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1032 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1033 return ldb_next_request(module, req);
1036 /* Firstly ensure we are not trying to rename it to be a child of itself */
1037 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
1038 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1039 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1040 ldb_dn_get_linearized(req->op.rename.olddn));
1041 return LDB_ERR_UNWILLING_TO_PERFORM;
1044 ac = oc_init_context(module, req);
1045 if (ac == NULL) {
1046 return LDB_ERR_OPERATIONS_ERROR;
1049 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1050 if (parent_dn == NULL) {
1051 ldb_oom(ldb);
1052 return LDB_ERR_OPERATIONS_ERROR;
1056 it makes a search request, looking for the parent DN to fix up the new DN
1057 to a standard one, at objectclass_do_rename()
1059 ret = ldb_build_search_req(&search_req, ldb,
1060 ac, parent_dn, LDB_SCOPE_BASE,
1061 "(objectClass=*)",
1062 attrs, NULL,
1063 ac, get_search_callback,
1064 req);
1065 if (ret != LDB_SUCCESS) {
1066 return ret;
1069 /* we have to add the show deleted control, as otherwise DRS
1070 deletes will be refused as we will think the target parent
1071 does not exist */
1072 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1074 if (ret != LDB_SUCCESS) {
1075 return ret;
1078 ac->step_fn = objectclass_do_rename;
1080 return ldb_next_request(ac->module, search_req);
1085 static int objectclass_do_rename(struct oc_context *ac)
1087 struct ldb_context *ldb;
1088 struct ldb_request *rename_req;
1089 struct ldb_dn *fixed_dn;
1090 int ret;
1092 ldb = ldb_module_get_ctx(ac->module);
1094 /* Check we have a valid parent */
1095 if (ac->search_res == NULL) {
1096 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1097 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1098 return LDB_ERR_UNWILLING_TO_PERFORM;
1101 /* Fix up the DN to be in the standard form,
1102 * taking particular care to match the parent DN */
1103 ret = fix_dn(ac,
1104 ac->req->op.rename.newdn,
1105 ac->search_res->message->dn,
1106 &fixed_dn);
1107 if (ret != LDB_SUCCESS) {
1108 return ret;
1111 /* TODO: Check this is a valid child to this parent,
1112 * by reading the allowedChildClasses and
1113 * allowedChildClasssesEffective attributes */
1115 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1116 ac->req->op.rename.olddn, fixed_dn,
1117 ac->req->controls,
1118 ac, oc_op_callback,
1119 ac->req);
1120 if (ret != LDB_SUCCESS) {
1121 return ret;
1124 /* perform the rename */
1125 return ldb_next_request(ac->module, rename_req);
1128 static int objectclass_init(struct ldb_module *module)
1130 struct ldb_context *ldb = ldb_module_get_ctx(module);
1131 int ret;
1132 /* Init everything else */
1133 ret = ldb_next_init(module);
1134 if (ret != LDB_SUCCESS) {
1135 return ret;
1138 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1139 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1141 return ret;
1144 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1145 .name = "objectclass",
1146 .add = objectclass_add,
1147 .modify = objectclass_modify,
1148 .rename = objectclass_rename,
1149 .init_context = objectclass_init