s4:objectclass LDB module - handle the case when there is a retry to add the root...
[Samba.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
blob4cbb1897fe8a298ab58704f07ebcd4d78ced0476
1 /*
2 ldb database library
4 Copyright (C) Simo Sorce 2006-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6 Copyright (C) Matthias Dieter Wallnöfer 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Name: ldb
25 * Component: objectClass sorting and constraint checking module
27 * Description:
28 * - sort the objectClass attribute into the class
29 * hierarchy and perform constraint checks (correct RDN name,
30 * valid parent),
31 * - fix DNs into 'standard' case
32 * - Add objectCategory and some other attribute defaults
34 * Author: Andrew Bartlett
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "util/dlinklist.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "librpc/ndr/libndr.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "libcli/security/security.h"
45 #include "auth/auth.h"
46 #include "param/param.h"
47 #include "../libds/common/flags.h"
48 #include "util.h"
50 struct oc_context {
52 struct ldb_module *module;
53 struct ldb_request *req;
54 const struct dsdb_schema *schema;
56 struct ldb_reply *search_res;
57 struct ldb_reply *search_res2;
59 int (*step_fn)(struct oc_context *);
62 struct class_list {
63 struct class_list *prev, *next;
64 const struct dsdb_class *objectclass;
67 static struct oc_context *oc_init_context(struct ldb_module *module,
68 struct ldb_request *req)
70 struct ldb_context *ldb;
71 struct oc_context *ac;
73 ldb = ldb_module_get_ctx(module);
75 ac = talloc_zero(req, struct oc_context);
76 if (ac == NULL) {
77 ldb_oom(ldb);
78 return NULL;
81 ac->module = module;
82 ac->req = req;
83 ac->schema = dsdb_get_schema(ldb, ac);
85 return ac;
88 static int objectclass_do_add(struct oc_context *ac);
90 /* Sort objectClasses into correct order, and validate that all
91 * objectClasses specified actually exist in the schema
94 static int objectclass_sort(struct ldb_module *module,
95 const struct dsdb_schema *schema,
96 TALLOC_CTX *mem_ctx,
97 struct ldb_message_element *objectclass_element,
98 struct class_list **sorted_out)
100 struct ldb_context *ldb;
101 unsigned int i, lowest;
102 struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
104 ldb = ldb_module_get_ctx(module);
106 /* DESIGN:
108 * We work on 4 different 'bins' (implemented here as linked lists):
110 * * sorted: the eventual list, in the order we wish to push
111 * into the database. This is the only ordered list.
113 * * parent_class: The current parent class 'bin' we are
114 * trying to find subclasses for
116 * * subclass: The subclasses we have found so far
118 * * unsorted: The remaining objectClasses
120 * The process is a matter of filtering objectClasses up from
121 * unsorted into sorted. Order is irrelevent in the later 3 'bins'.
123 * We start with 'top' (found and promoted to parent_class
124 * initially). Then we find (in unsorted) all the direct
125 * subclasses of 'top'. parent_classes is concatenated onto
126 * the end of 'sorted', and subclass becomes the list in
127 * parent_class.
129 * We then repeat, until we find no more subclasses. Any left
130 * over classes are added to the end.
134 /* Firstly, dump all the objectClass elements into the
135 * unsorted bin, except for 'top', which is special */
136 for (i=0; i < objectclass_element->num_values; i++) {
137 current = talloc(mem_ctx, struct class_list);
138 if (!current) {
139 ldb_oom(ldb);
140 return LDB_ERR_OPERATIONS_ERROR;
142 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
143 if (!current->objectclass) {
144 ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema",
145 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146 /* This looks weird, but windows apparently returns this for invalid objectClass values */
147 return LDB_ERR_NO_SUCH_ATTRIBUTE;
148 } else if (current->objectclass->isDefunct) {
149 ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects",
150 (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
151 /* This looks weird, but windows apparently returns this for invalid objectClass values */
152 return LDB_ERR_NO_SUCH_ATTRIBUTE;
155 /* Don't add top to list, we will do that later */
156 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
157 DLIST_ADD_END(unsorted, current, struct class_list *);
161 /* Add top here, to prevent duplicates */
162 current = talloc(mem_ctx, struct class_list);
163 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
164 DLIST_ADD_END(sorted, current, struct class_list *);
167 /* For each object: find parent chain */
168 for (current = unsorted; schema && current; current = current->next) {
169 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
170 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
171 break;
174 /* If we didn't get to the end of the list, we need to add this parent */
175 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
176 continue;
179 new_parent = talloc(mem_ctx, struct class_list);
180 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
181 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
186 lowest = UINT_MAX;
187 current_lowest = NULL;
188 for (current = unsorted; schema && current; current = current->next) {
189 if(current->objectclass->subClass_order < lowest) {
190 current_lowest = current;
191 lowest = current->objectclass->subClass_order;
195 if(current_lowest != NULL) {
196 DLIST_REMOVE(unsorted,current_lowest);
197 DLIST_ADD_END(sorted,current_lowest, struct class_list *);
199 } while(unsorted);
202 if (!unsorted) {
203 *sorted_out = sorted;
204 return LDB_SUCCESS;
207 if (!schema) {
208 /* If we don't have schema yet, then just merge the lists again */
209 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
210 *sorted_out = sorted;
211 return LDB_SUCCESS;
214 /* This shouldn't happen, and would break MMC, perhaps there
215 * was no 'top', a conflict in the objectClasses or some other
216 * schema error?
218 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
219 return LDB_ERR_OBJECT_CLASS_VIOLATION;
222 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
224 struct ldb_context *ldb;
225 struct oc_context *ac;
226 int ret;
228 ac = talloc_get_type(req->context, struct oc_context);
229 ldb = ldb_module_get_ctx(ac->module);
231 if (!ares) {
232 return ldb_module_done(ac->req, NULL, NULL,
233 LDB_ERR_OPERATIONS_ERROR);
235 if (ares->error != LDB_SUCCESS &&
236 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
237 return ldb_module_done(ac->req, ares->controls,
238 ares->response, ares->error);
241 ldb_reset_err_string(ldb);
243 switch (ares->type) {
244 case LDB_REPLY_ENTRY:
245 if (ac->search_res != NULL) {
246 ldb_set_errstring(ldb, "Too many results");
247 talloc_free(ares);
248 return ldb_module_done(ac->req, NULL, NULL,
249 LDB_ERR_OPERATIONS_ERROR);
252 ac->search_res = talloc_steal(ac, ares);
253 break;
255 case LDB_REPLY_REFERRAL:
256 /* ignore */
257 talloc_free(ares);
258 break;
260 case LDB_REPLY_DONE:
261 talloc_free(ares);
262 ret = ac->step_fn(ac);
263 if (ret != LDB_SUCCESS) {
264 return ldb_module_done(ac->req, NULL, NULL, ret);
266 break;
269 return LDB_SUCCESS;
272 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
274 struct oc_context *ac;
276 ac = talloc_get_type(req->context, struct oc_context);
278 if (!ares) {
279 return ldb_module_done(ac->req, NULL, NULL,
280 LDB_ERR_OPERATIONS_ERROR);
283 if (ares->type == LDB_REPLY_REFERRAL) {
284 return ldb_module_send_referral(ac->req, ares->referral);
287 if (ares->error != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, ares->controls,
289 ares->response, ares->error);
292 if (ares->type != LDB_REPLY_DONE) {
293 talloc_free(ares);
294 return ldb_module_done(ac->req, NULL, NULL,
295 LDB_ERR_OPERATIONS_ERROR);
298 return ldb_module_done(ac->req, ares->controls,
299 ares->response, ares->error);
302 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
304 This should mean that if the parent is:
305 CN=Users,DC=samba,DC=example,DC=com
306 and a proposed child is
307 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
309 The resulting DN should be:
311 CN=Admins,CN=Users,DC=samba,DC=example,DC=com
314 static int fix_dn(TALLOC_CTX *mem_ctx,
315 struct ldb_dn *newdn, struct ldb_dn *parent_dn,
316 struct ldb_dn **fixed_dn)
318 char *upper_rdn_attr;
319 const struct ldb_val *rdn_val;
321 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
322 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
324 /* We need the attribute name in upper case */
325 upper_rdn_attr = strupper_talloc(*fixed_dn,
326 ldb_dn_get_rdn_name(newdn));
327 if (!upper_rdn_attr) {
328 return LDB_ERR_OPERATIONS_ERROR;
331 /* Create a new child */
332 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
333 return LDB_ERR_OPERATIONS_ERROR;
337 rdn_val = ldb_dn_get_rdn_val(newdn);
339 #if 0
340 /* the rules for rDN length constraints are more complex than
341 this. Until we understand them we need to leave this
342 constraint out. Otherwise we break replication, as windows
343 does sometimes send us rDNs longer than 64 */
344 if (!rdn_val || rdn_val->length > 64) {
345 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
347 #endif
350 /* And replace it with CN=foo (we need the attribute in upper case */
351 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
355 static int objectclass_do_add(struct oc_context *ac);
357 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
359 struct ldb_context *ldb;
360 struct ldb_request *search_req;
361 struct oc_context *ac;
362 struct ldb_dn *parent_dn;
363 const struct ldb_val *val;
364 char *value;
365 int ret;
366 static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
368 ldb = ldb_module_get_ctx(module);
370 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
372 /* do not manipulate our control entries */
373 if (ldb_dn_is_special(req->op.add.message->dn)) {
374 return ldb_next_request(module, req);
377 /* An add operation on the root basedn has a special handling when the
378 * relax control isn't specified. */
379 if (ldb_dn_compare(ldb_get_root_basedn(ldb), req->op.add.message->dn) == 0) {
380 if (ldb_request_get_control(req,
381 LDB_CONTROL_RELAX_OID) == NULL) {
382 /* When we are trying to readd the root basedn then
383 * this is denied, but with an interesting mechanism:
384 * there is generated a referral with the last
385 * component value as hostname. */
386 val = ldb_dn_get_component_val(req->op.add.message->dn,
387 ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
388 if (val == NULL) {
389 return LDB_ERR_OPERATIONS_ERROR;
391 value = talloc_asprintf(req, "ldap://%s/%s", val->data,
392 ldb_dn_get_linearized(req->op.add.message->dn));
393 if (value == NULL) {
394 return LDB_ERR_OPERATIONS_ERROR;
397 return ldb_module_send_referral(req, value);
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;
434 ac->step_fn = objectclass_do_add;
436 return ldb_next_request(ac->module, search_req);
439 static int objectclass_do_add(struct oc_context *ac)
441 struct ldb_context *ldb;
442 struct ldb_request *add_req;
443 struct ldb_message_element *objectclass_element, *el;
444 struct ldb_message *msg;
445 TALLOC_CTX *mem_ctx;
446 struct class_list *sorted, *current;
447 const char *rdn_name = NULL;
448 char *value;
449 const struct dsdb_class *objectclass;
450 int32_t systemFlags = 0;
451 int ret;
453 ldb = ldb_module_get_ctx(ac->module);
455 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
457 /* Check if we have a valid parent - this check is needed since
458 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
459 if (ac->search_res == NULL) {
460 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
461 /* Allow the tree to be started but don't keep any
462 * error strings - they're meaningless. */
463 ldb_set_errstring(ldb, NULL);
464 } else {
465 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!",
466 ldb_dn_get_linearized(msg->dn));
467 return LDB_ERR_NO_SUCH_OBJECT;
469 } else {
470 /* Fix up the DN to be in the standard form, taking
471 * particular care to match the parent DN */
472 ret = fix_dn(msg,
473 ac->req->op.add.message->dn,
474 ac->search_res->message->dn,
475 &msg->dn);
476 if (ret != LDB_SUCCESS) {
477 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
478 ldb_dn_get_linearized(ac->req->op.add.message->dn));
479 return ret;
483 mem_ctx = talloc_new(ac);
484 if (mem_ctx == NULL) {
485 ldb_oom(ldb);
486 return LDB_ERR_OPERATIONS_ERROR;
489 if (ac->schema != NULL) {
490 /* This is now the objectClass list from the database */
491 objectclass_element = ldb_msg_find_element(msg, "objectClass");
493 if (!objectclass_element) {
494 /* Where did it go? bail now... */
495 talloc_free(mem_ctx);
496 return LDB_ERR_OPERATIONS_ERROR;
498 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
499 objectclass_element, &sorted);
500 if (ret != LDB_SUCCESS) {
501 talloc_free(mem_ctx);
502 return ret;
505 ldb_msg_remove_attr(msg, "objectClass");
506 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
508 if (ret != LDB_SUCCESS) {
509 talloc_free(mem_ctx);
510 return ret;
513 /* We must completely replace the existing objectClass entry,
514 * because we need it sorted */
516 /* Move from the linked list back into an ldb msg */
517 for (current = sorted; current; current = current->next) {
518 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
519 if (value == NULL) {
520 ldb_oom(ldb);
521 talloc_free(mem_ctx);
522 return LDB_ERR_OPERATIONS_ERROR;
524 ret = ldb_msg_add_string(msg, "objectClass", value);
525 if (ret != LDB_SUCCESS) {
526 ldb_set_errstring(ldb,
527 "objectclass: could not re-add sorted "
528 "objectclass to modify msg");
529 talloc_free(mem_ctx);
530 return ret;
534 /* Retrive the message again so get_last_structural_class works */
535 objectclass_element = ldb_msg_find_element(msg, "objectClass");
537 /* Make sure its valid to add an object of this type */
538 objectclass = get_last_structural_class(ac->schema,
539 objectclass_element);
540 if(objectclass == NULL) {
541 ldb_asprintf_errstring(ldb,
542 "Failed to find a structural class for %s",
543 ldb_dn_get_linearized(msg->dn));
544 return LDB_ERR_UNWILLING_TO_PERFORM;
547 rdn_name = ldb_dn_get_rdn_name(msg->dn);
548 if (objectclass->rDNAttID
549 && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
550 ldb_asprintf_errstring(ldb,
551 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
552 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
553 return LDB_ERR_NAMING_VIOLATION;
556 if (ac->search_res && ac->search_res->message) {
557 struct ldb_message_element *oc_el
558 = ldb_msg_find_element(ac->search_res->message, "objectClass");
560 bool allowed_class = false;
561 unsigned int i, j;
562 for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
563 const struct dsdb_class *sclass;
565 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
566 &oc_el->values[i]);
567 if (!sclass) {
568 /* We don't know this class? what is going on? */
569 continue;
571 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
572 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
573 allowed_class = true;
574 break;
579 if (!allowed_class) {
580 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
581 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
582 return LDB_ERR_NAMING_VIOLATION;
586 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
587 ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
588 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
589 return LDB_ERR_UNWILLING_TO_PERFORM;
592 if (!ldb_msg_find_element(msg, "objectCategory")) {
593 struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
594 if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
595 /* Strip off extended components */
596 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
597 value = ldb_dn_alloc_linearized(msg, dn);
598 talloc_free(dn);
599 } else {
600 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
602 if (value == NULL) {
603 ldb_oom(ldb);
604 talloc_free(mem_ctx);
605 return LDB_ERR_OPERATIONS_ERROR;
607 ldb_msg_add_string(msg, "objectCategory", value);
609 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
610 ldb_msg_add_string(msg, "showInAdvancedViewOnly",
611 "TRUE");
614 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
615 el = ldb_msg_find_element(msg, "systemFlags");
617 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
619 if (el) {
620 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
621 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
622 ldb_msg_remove_element(msg, el);
625 /* This flag is only allowed on attributeSchema objects */
626 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
627 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
630 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
631 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
632 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
633 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
634 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
635 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
637 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
638 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
639 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
640 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
643 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
645 if (el || systemFlags != 0) {
646 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
650 talloc_free(mem_ctx);
651 ret = ldb_msg_sanity_check(ldb, msg);
654 if (ret != LDB_SUCCESS) {
655 return ret;
658 ret = ldb_build_add_req(&add_req, ldb, ac,
659 msg,
660 ac->req->controls,
661 ac, oc_op_callback,
662 ac->req);
663 if (ret != LDB_SUCCESS) {
664 return ret;
667 /* perform the add */
668 return ldb_next_request(ac->module, add_req);
671 static int oc_modify_callback(struct ldb_request *req,
672 struct ldb_reply *ares);
673 static int objectclass_do_mod(struct oc_context *ac);
675 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
677 struct ldb_context *ldb = ldb_module_get_ctx(module);
678 struct ldb_message_element *objectclass_element;
679 struct ldb_message *msg;
680 struct ldb_request *down_req;
681 struct oc_context *ac;
682 bool oc_changes = false;
683 int ret;
685 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
687 /* do not manipulate our control entries */
688 if (ldb_dn_is_special(req->op.mod.message->dn)) {
689 return ldb_next_request(module, req);
692 /* As with the "real" AD we don't accept empty messages */
693 if (req->op.mod.message->num_elements == 0) {
694 ldb_set_errstring(ldb, "objectclass: modify message must have "
695 "elements/attributes!");
696 return LDB_ERR_UNWILLING_TO_PERFORM;
699 ac = oc_init_context(module, req);
700 if (ac == NULL) {
701 return LDB_ERR_OPERATIONS_ERROR;
704 /* Without schema, there isn't much to do here */
705 if (ac->schema == NULL) {
706 talloc_free(ac);
707 return ldb_next_request(module, req);
710 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
711 if (msg == NULL) {
712 return LDB_ERR_OPERATIONS_ERROR;
715 /* For now change everything except the objectclasses */
717 objectclass_element = ldb_msg_find_element(msg, "objectClass");
718 if (objectclass_element != NULL) {
719 ldb_msg_remove_attr(msg, "objectClass");
720 oc_changes = true;
723 ret = ldb_build_mod_req(&down_req, ldb, ac,
724 msg,
725 req->controls, ac,
726 oc_changes ? oc_modify_callback : oc_op_callback,
727 req);
728 if (ret != LDB_SUCCESS) {
729 return ret;
732 return ldb_next_request(module, down_req);
735 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
737 static const char * const attrs[] = { "objectClass", NULL };
738 struct ldb_context *ldb;
739 struct ldb_request *search_req;
740 struct oc_context *ac;
741 int ret;
743 ac = talloc_get_type(req->context, struct oc_context);
744 ldb = ldb_module_get_ctx(ac->module);
746 if (!ares) {
747 return ldb_module_done(ac->req, NULL, NULL,
748 LDB_ERR_OPERATIONS_ERROR);
751 if (ares->type == LDB_REPLY_REFERRAL) {
752 return ldb_module_send_referral(ac->req, ares->referral);
755 if (ares->error != LDB_SUCCESS) {
756 return ldb_module_done(ac->req, ares->controls,
757 ares->response, ares->error);
760 if (ares->type != LDB_REPLY_DONE) {
761 talloc_free(ares);
762 return ldb_module_done(ac->req, NULL, NULL,
763 LDB_ERR_OPERATIONS_ERROR);
766 talloc_free(ares);
768 /* this looks up the real existing object for fetching some important
769 * informations (objectclasses) */
770 ret = ldb_build_search_req(&search_req, ldb,
771 ac, ac->req->op.mod.message->dn,
772 LDB_SCOPE_BASE,
773 "(objectClass=*)",
774 attrs, NULL,
775 ac, get_search_callback,
776 ac->req);
777 if (ret != LDB_SUCCESS) {
778 return ldb_module_done(ac->req, NULL, NULL, ret);
781 ac->step_fn = objectclass_do_mod;
783 ret = ldb_next_request(ac->module, search_req);
784 if (ret != LDB_SUCCESS) {
785 return ldb_module_done(ac->req, NULL, NULL, ret);
788 return LDB_SUCCESS;
791 static int objectclass_do_mod(struct oc_context *ac)
793 struct ldb_context *ldb;
794 struct ldb_request *mod_req;
795 char *value;
796 struct ldb_message_element *oc_el_entry, *oc_el_change;
797 struct ldb_val *vals;
798 struct ldb_message *msg;
799 TALLOC_CTX *mem_ctx;
800 struct class_list *sorted, *current;
801 const struct dsdb_class *objectclass;
802 unsigned int i, j;
803 bool found, replace = false;
804 int ret;
806 ldb = ldb_module_get_ctx(ac->module);
808 /* we should always have a valid entry when we enter here */
809 if (ac->search_res == NULL) {
810 return LDB_ERR_OPERATIONS_ERROR;
813 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
814 "objectClass");
815 if (oc_el_entry == NULL) {
816 /* existing entry without a valid object class? */
817 return LDB_ERR_OPERATIONS_ERROR;
820 oc_el_change = ldb_msg_find_element(ac->req->op.mod.message,
821 "objectClass");
822 if (oc_el_change == NULL) {
823 /* we should have an objectclass change operation */
824 return LDB_ERR_OPERATIONS_ERROR;
827 /* use a new message structure */
828 msg = ldb_msg_new(ac);
829 if (msg == NULL) {
830 ldb_oom(ldb);
831 return LDB_ERR_OPERATIONS_ERROR;
834 msg->dn = ac->req->op.mod.message->dn;
836 mem_ctx = talloc_new(ac);
837 if (mem_ctx == NULL) {
838 ldb_oom(ldb);
839 return LDB_ERR_OPERATIONS_ERROR;
842 switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
843 case LDB_FLAG_MOD_ADD:
844 /* Merge the two message elements */
845 for (i = 0; i < oc_el_change->num_values; i++) {
846 for (j = 0; j < oc_el_entry->num_values; j++) {
847 if (strcasecmp((char *)oc_el_change->values[i].data,
848 (char *)oc_el_entry->values[j].data) == 0) {
849 /* we cannot add an already existing object class */
850 talloc_free(mem_ctx);
851 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
854 /* append the new object class value - code was copied
855 * from "ldb_msg_add_value" */
856 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
857 struct ldb_val,
858 oc_el_entry->num_values + 1);
859 if (vals == NULL) {
860 ldb_oom(ldb);
861 talloc_free(mem_ctx);
862 return LDB_ERR_OPERATIONS_ERROR;
864 oc_el_entry->values = vals;
865 oc_el_entry->values[oc_el_entry->num_values] =
866 oc_el_change->values[i];
867 ++(oc_el_entry->num_values);
870 objectclass = get_last_structural_class(ac->schema,
871 oc_el_change);
872 if (objectclass != NULL) {
873 /* we cannot add a new structural object class */
874 talloc_free(mem_ctx);
875 return LDB_ERR_OBJECT_CLASS_VIOLATION;
878 /* Now do the sorting */
879 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
880 oc_el_entry, &sorted);
881 if (ret != LDB_SUCCESS) {
882 talloc_free(mem_ctx);
883 return ret;
886 break;
888 case LDB_FLAG_MOD_REPLACE:
889 /* Do the sorting for the change message element */
890 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
891 oc_el_change, &sorted);
892 if (ret != LDB_SUCCESS) {
893 talloc_free(mem_ctx);
894 return ret;
897 /* this is a replace */
898 replace = true;
900 break;
902 case LDB_FLAG_MOD_DELETE:
903 /* get the actual top-most structural objectclass */
904 objectclass = get_last_structural_class(ac->schema,
905 oc_el_entry);
906 if (objectclass == NULL) {
907 talloc_free(mem_ctx);
908 return LDB_ERR_OPERATIONS_ERROR;
911 /* Merge the two message elements */
912 for (i = 0; i < oc_el_change->num_values; i++) {
913 found = false;
914 for (j = 0; j < oc_el_entry->num_values; j++) {
915 if (strcasecmp((char *)oc_el_change->values[i].data,
916 (char *)oc_el_entry->values[j].data) == 0) {
917 found = true;
918 /* delete the object class value -
919 * code was copied from
920 * "ldb_msg_remove_element" */
921 if (j != oc_el_entry->num_values - 1) {
922 memmove(&oc_el_entry->values[j],
923 &oc_el_entry->values[j+1],
924 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
926 --(oc_el_entry->num_values);
927 break;
930 if (!found) {
931 /* we cannot delete a not existing object class */
932 talloc_free(mem_ctx);
933 return LDB_ERR_NO_SUCH_ATTRIBUTE;
937 /* Make sure that the top-most structural objectclass wasn't
938 * deleted */
939 found = false;
940 for (i = 0; i < oc_el_entry->num_values; i++) {
941 if (strcasecmp(objectclass->lDAPDisplayName,
942 (char *)oc_el_entry->values[i].data) == 0) {
943 found = true; break;
946 if (!found) {
947 talloc_free(mem_ctx);
948 return LDB_ERR_OBJECT_CLASS_VIOLATION;
952 /* Now do the sorting */
953 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
954 oc_el_entry, &sorted);
955 if (ret != LDB_SUCCESS) {
956 talloc_free(mem_ctx);
957 return ret;
960 break;
963 ret = ldb_msg_add_empty(msg, "objectClass",
964 LDB_FLAG_MOD_REPLACE, &oc_el_change);
965 if (ret != LDB_SUCCESS) {
966 ldb_oom(ldb);
967 talloc_free(mem_ctx);
968 return ret;
971 /* Move from the linked list back into an ldb msg */
972 for (current = sorted; current; current = current->next) {
973 value = talloc_strdup(msg,
974 current->objectclass->lDAPDisplayName);
975 if (value == NULL) {
976 ldb_oom(ldb);
977 talloc_free(mem_ctx);
978 return LDB_ERR_OPERATIONS_ERROR;
980 ret = ldb_msg_add_string(msg, "objectClass", value);
981 if (ret != LDB_SUCCESS) {
982 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
983 talloc_free(mem_ctx);
984 return ret;
988 talloc_free(mem_ctx);
990 if (replace) {
991 /* Well, on replace we are nearly done: we have to test if
992 * the change and entry message element are identically. We
993 * can use "ldb_msg_element_compare" since now the specified
994 * objectclasses match for sure in case. */
995 ret = ldb_msg_element_compare(oc_el_entry, oc_el_change);
996 if (ret == 0) {
997 ret = ldb_msg_element_compare(oc_el_change,
998 oc_el_entry);
1000 if (ret == 0) {
1001 /* they are the same so we are done in this case */
1002 return ldb_module_done(ac->req, NULL, NULL,
1003 LDB_SUCCESS);
1004 } else {
1005 /* they're not exactly the same */
1006 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1010 /* in the other cases we have the real change left to do */
1012 ret = ldb_msg_sanity_check(ldb, msg);
1013 if (ret != LDB_SUCCESS) {
1014 return ret;
1017 ret = ldb_build_mod_req(&mod_req, ldb, ac,
1018 msg,
1019 ac->req->controls,
1020 ac, oc_op_callback,
1021 ac->req);
1022 if (ret != LDB_SUCCESS) {
1023 return ret;
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[] = { "objectClass", 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 /* do not manipulate our control entries */
1045 if (ldb_dn_is_special(req->op.rename.newdn)) {
1046 return ldb_next_request(module, req);
1049 ac = oc_init_context(module, req);
1050 if (ac == NULL) {
1051 return LDB_ERR_OPERATIONS_ERROR;
1054 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1055 if (parent_dn == NULL) {
1056 ldb_oom(ldb);
1057 return LDB_ERR_OPERATIONS_ERROR;
1060 /* this looks up the parent object for fetching some important
1061 * informations (objectclasses, DN normalisation...) */
1062 ret = ldb_build_search_req(&search_req, ldb,
1063 ac, parent_dn, LDB_SCOPE_BASE,
1064 "(objectClass=*)",
1065 attrs, NULL,
1066 ac, get_search_callback,
1067 req);
1068 if (ret != LDB_SUCCESS) {
1069 return ret;
1072 /* we have to add the show deleted control, as otherwise DRS
1073 deletes will be refused as we will think the target parent
1074 does not exist */
1075 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1077 if (ret != LDB_SUCCESS) {
1078 return ret;
1081 ac->step_fn = objectclass_do_rename;
1083 return ldb_next_request(ac->module, search_req);
1086 static int objectclass_do_rename2(struct oc_context *ac);
1088 static int objectclass_do_rename(struct oc_context *ac)
1090 static const char * const attrs[] = { "objectClass", NULL };
1091 struct ldb_context *ldb;
1092 struct ldb_request *search_req;
1093 int ret;
1095 ldb = ldb_module_get_ctx(ac->module);
1097 /* Check if we have a valid parent - this check is needed since
1098 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1099 if (ac->search_res == NULL) {
1100 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1101 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1102 return LDB_ERR_OTHER;
1105 /* now assign "search_res2" to the parent entry to have "search_res"
1106 * free for another lookup */
1107 ac->search_res2 = ac->search_res;
1108 ac->search_res = NULL;
1110 /* this looks up the real existing object for fetching some important
1111 * informations (objectclasses) */
1112 ret = ldb_build_search_req(&search_req, ldb,
1113 ac, ac->req->op.rename.olddn,
1114 LDB_SCOPE_BASE,
1115 "(objectClass=*)",
1116 attrs, NULL,
1117 ac, get_search_callback,
1118 ac->req);
1119 if (ret != LDB_SUCCESS) {
1120 return ret;
1123 ac->step_fn = objectclass_do_rename2;
1125 return ldb_next_request(ac->module, search_req);
1128 static int objectclass_do_rename2(struct oc_context *ac)
1130 struct ldb_context *ldb;
1131 struct ldb_request *rename_req;
1132 struct ldb_dn *fixed_dn;
1133 int ret;
1135 ldb = ldb_module_get_ctx(ac->module);
1137 /* Check if we have a valid entry - this check is needed since
1138 * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1139 if (ac->search_res == NULL) {
1140 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1141 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1142 return LDB_ERR_NO_SUCH_OBJECT;
1145 if (ac->schema != NULL) {
1146 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1147 const struct dsdb_class *objectclass;
1148 const char *rdn_name;
1149 bool allowed_class = false;
1150 unsigned int i, j;
1152 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1153 "objectClass");
1154 if (oc_el_entry == NULL) {
1155 /* existing entry without a valid object class? */
1156 return LDB_ERR_OPERATIONS_ERROR;
1158 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1159 if (objectclass == NULL) {
1160 /* existing entry without a valid object class? */
1161 return LDB_ERR_OPERATIONS_ERROR;
1164 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1165 if ((objectclass->rDNAttID != NULL) &&
1166 (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1167 ldb_asprintf_errstring(ldb,
1168 "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1169 rdn_name,
1170 objectclass->lDAPDisplayName,
1171 objectclass->rDNAttID);
1172 return LDB_ERR_UNWILLING_TO_PERFORM;
1175 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1176 "objectClass");
1177 if (oc_el_parent == NULL) {
1178 /* existing entry without a valid object class? */
1179 return LDB_ERR_OPERATIONS_ERROR;
1182 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1183 const struct dsdb_class *sclass;
1185 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1186 &oc_el_parent->values[i]);
1187 if (!sclass) {
1188 /* We don't know this class? what is going on? */
1189 continue;
1191 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1192 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1193 allowed_class = true;
1194 break;
1199 if (!allowed_class) {
1200 ldb_asprintf_errstring(ldb,
1201 "objectclass: structural objectClass %s is not a valid child class for %s",
1202 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1203 return LDB_ERR_NAMING_VIOLATION;
1207 /* Ensure we are not trying to rename it to be a child of itself */
1208 if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1209 ac->req->op.rename.newdn) == 0) &&
1210 (ldb_dn_compare(ac->req->op.rename.olddn,
1211 ac->req->op.rename.newdn) != 0)) {
1212 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1213 ldb_dn_get_linearized(ac->req->op.rename.olddn));
1214 return LDB_ERR_UNWILLING_TO_PERFORM;
1217 /* Fix up the DN to be in the standard form, taking
1218 * particular care to match the parent DN */
1219 ret = fix_dn(ac,
1220 ac->req->op.rename.newdn,
1221 ac->search_res2->message->dn,
1222 &fixed_dn);
1223 if (ret != LDB_SUCCESS) {
1224 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1225 ldb_dn_get_linearized(ac->req->op.rename.newdn));
1226 return ret;
1230 ret = ldb_build_rename_req(&rename_req, ldb, ac,
1231 ac->req->op.rename.olddn, fixed_dn,
1232 ac->req->controls,
1233 ac, oc_op_callback,
1234 ac->req);
1235 if (ret != LDB_SUCCESS) {
1236 return ret;
1239 /* perform the rename */
1240 return ldb_next_request(ac->module, rename_req);
1243 static int objectclass_init(struct ldb_module *module)
1245 struct ldb_context *ldb = ldb_module_get_ctx(module);
1246 int ret;
1247 /* Init everything else */
1248 ret = ldb_next_init(module);
1249 if (ret != LDB_SUCCESS) {
1250 return ret;
1253 /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1254 ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1256 return ret;
1259 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1260 .name = "objectclass",
1261 .add = objectclass_add,
1262 .modify = objectclass_modify,
1263 .rename = objectclass_rename,
1264 .init_context = objectclass_init