1/* 2 ldb database library 3 4 Copyright (C) Simo Sorce 2006-2008 5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007 6 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. 11 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. 16 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/>. 19*/ 20 21/* 22 * Name: ldb 23 * 24 * Component: objectClass sorting module 25 * 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 31 * 32 * Author: Andrew Bartlett 33 */ 34 35 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 46struct oc_context { 47 48 struct ldb_module *module; 49 struct ldb_request *req; 50 51 struct ldb_reply *search_res; 52 53 int (*step_fn)(struct oc_context *); 54}; 55 56struct class_list { 57 struct class_list *prev, *next; 58 const struct dsdb_class *objectclass; 59}; 60 61static struct oc_context *oc_init_context(struct ldb_module *module, 62 struct ldb_request *req) 63{ 64 struct ldb_context *ldb; 65 struct oc_context *ac; 66 67 ldb = ldb_module_get_ctx(module); 68 69 ac = talloc_zero(req, struct oc_context); 70 if (ac == NULL) { 71 ldb_set_errstring(ldb, "Out of Memory"); 72 return NULL; 73 } 74 75 ac->module = module; 76 ac->req = req; 77 78 return ac; 79} 80 81static int objectclass_do_add(struct oc_context *ac); 82 83/* Sort objectClasses into correct order, and validate that all 84 * objectClasses specified actually exist in the schema 85 */ 86 87static int objectclass_sort(struct ldb_module *module, 88 const struct dsdb_schema *schema, 89 TALLOC_CTX *mem_ctx, 90 struct ldb_message_element *objectclass_element, 91 struct class_list **sorted_out) 92{ 93 struct ldb_context *ldb; 94 int i; 95 int layer; 96 struct class_list *sorted = NULL, *parent_class = NULL, 97 *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent; 98 99 ldb = ldb_module_get_ctx(module); 100 101 /* DESIGN: 102 * 103 * We work on 4 different 'bins' (implemented here as linked lists): 104 * 105 * * sorted: the eventual list, in the order we wish to push 106 * into the database. This is the only ordered list. 107 * 108 * * parent_class: The current parent class 'bin' we are 109 * trying to find subclasses for 110 * 111 * * subclass: The subclasses we have found so far 112 * 113 * * unsorted: The remaining objectClasses 114 * 115 * The process is a matter of filtering objectClasses up from 116 * unsorted into sorted. Order is irrelevent in the later 3 'bins'. 117 * 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. 123 * 124 * We then repeat, until we find no more subclasses. Any left 125 * over classes are added to the end. 126 * 127 */ 128 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; 136 } 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 return LDB_ERR_OBJECT_CLASS_VIOLATION; 142 } 143 144 /* this is the root of the tree. We will start 145 * looking for subclasses from here */ 146 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) { 147 DLIST_ADD_END(parent_class, current, struct class_list *); 148 } else { 149 DLIST_ADD_END(unsorted, current, struct class_list *); 150 } 151 } 152 153 if (parent_class == NULL) { 154 current = talloc(mem_ctx, struct class_list); 155 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top"); 156 DLIST_ADD_END(parent_class, current, struct class_list *); 157 } 158 159 /* For each object: find parent chain */ 160 for (current = unsorted; schema && current; current = current->next) { 161 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) { 162 if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) { 163 break; 164 } 165 } 166 /* If we didn't get to the end of the list, we need to add this parent */ 167 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) { 168 continue; 169 } 170 171 new_parent = talloc(mem_ctx, struct class_list); 172 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf); 173 DLIST_ADD_END(unsorted, new_parent, struct class_list *); 174 } 175 176 /* DEBUGGING aid: how many layers are we down now? */ 177 layer = 0; 178 do { 179 layer++; 180 /* Find all the subclasses of classes in the 181 * parent_classes. Push them onto the subclass list */ 182 183 /* Ensure we don't bother if there are no unsorted entries left */ 184 for (current = parent_class; schema && unsorted && current; current = current->next) { 185 /* Walk the list of possible subclasses in unsorted */ 186 for (poss_subclass = unsorted; poss_subclass; ) { 187 struct class_list *next; 188 189 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */ 190 next = poss_subclass->next; 191 192 if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) { 193 DLIST_REMOVE(unsorted, poss_subclass); 194 DLIST_ADD(subclass, poss_subclass); 195 196 break; 197 } 198 poss_subclass = next; 199 } 200 } 201 202 /* Now push the parent_classes as sorted, we are done with 203 these. Add to the END of the list by concatenation */ 204 DLIST_CONCATENATE(sorted, parent_class, struct class_list *); 205 206 /* and now find subclasses of these */ 207 parent_class = subclass; 208 subclass = NULL; 209 210 /* If we didn't find any subclasses we will fall out 211 * the bottom here */ 212 } while (parent_class); 213 214 if (!unsorted) { 215 *sorted_out = sorted; 216 return LDB_SUCCESS; 217 } 218 219 if (!schema) { 220 /* If we don't have schema yet, then just merge the lists again */ 221 DLIST_CONCATENATE(sorted, unsorted, struct class_list *); 222 *sorted_out = sorted; 223 return LDB_SUCCESS; 224 } 225 226 /* This shouldn't happen, and would break MMC, perhaps there 227 * was no 'top', a conflict in the objectClasses or some other 228 * schema error? 229 */ 230 ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName); 231 return LDB_ERR_OBJECT_CLASS_VIOLATION; 232} 233 234static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares) 235{ 236 struct ldb_context *ldb; 237 struct oc_context *ac; 238 int ret; 239 240 ac = talloc_get_type(req->context, struct oc_context); 241 ldb = ldb_module_get_ctx(ac->module); 242 243 if (!ares) { 244 return ldb_module_done(ac->req, NULL, NULL, 245 LDB_ERR_OPERATIONS_ERROR); 246 } 247 if (ares->error != LDB_SUCCESS && 248 ares->error != LDB_ERR_NO_SUCH_OBJECT) { 249 return ldb_module_done(ac->req, ares->controls, 250 ares->response, ares->error); 251 } 252 253 ldb_reset_err_string(ldb); 254 255 switch (ares->type) { 256 case LDB_REPLY_ENTRY: 257 if (ac->search_res != NULL) { 258 ldb_set_errstring(ldb, "Too many results"); 259 talloc_free(ares); 260 return ldb_module_done(ac->req, NULL, NULL, 261 LDB_ERR_OPERATIONS_ERROR); 262 } 263 264 ac->search_res = talloc_steal(ac, ares); 265 break; 266 267 case LDB_REPLY_REFERRAL: 268 /* ignore */ 269 talloc_free(ares); 270 break; 271 272 case LDB_REPLY_DONE: 273 talloc_free(ares); 274 ret = ac->step_fn(ac); 275 if (ret != LDB_SUCCESS) { 276 return ldb_module_done(ac->req, NULL, NULL, ret); 277 } 278 break; 279 } 280 281 return LDB_SUCCESS; 282} 283 284static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares) 285{ 286 struct oc_context *ac; 287 288 ac = talloc_get_type(req->context, struct oc_context); 289 290 if (!ares) { 291 return ldb_module_done(ac->req, NULL, NULL, 292 LDB_ERR_OPERATIONS_ERROR); 293 } 294 if (ares->error != LDB_SUCCESS) { 295 return ldb_module_done(ac->req, ares->controls, 296 ares->response, ares->error); 297 } 298 299 if (ares->type != LDB_REPLY_DONE) { 300 talloc_free(ares); 301 return ldb_module_done(ac->req, NULL, NULL, 302 LDB_ERR_OPERATIONS_ERROR); 303 } 304 305 return ldb_module_done(ac->req, ares->controls, 306 ares->response, ares->error); 307} 308 309/* Fix up the DN to be in the standard form, taking particular care to match the parent DN 310 311 This should mean that if the parent is: 312 CN=Users,DC=samba,DC=example,DC=com 313 and a proposed child is 314 cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM 315 316 The resulting DN should be: 317 318 CN=Admins,CN=Users,DC=samba,DC=example,DC=com 319 320 */ 321static int fix_dn(TALLOC_CTX *mem_ctx, 322 struct ldb_dn *newdn, struct ldb_dn *parent_dn, 323 struct ldb_dn **fixed_dn) 324{ 325 char *upper_rdn_attr; 326 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */ 327 *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn); 328 329 /* We need the attribute name in upper case */ 330 upper_rdn_attr = strupper_talloc(*fixed_dn, 331 ldb_dn_get_rdn_name(newdn)); 332 if (!upper_rdn_attr) { 333 return LDB_ERR_OPERATIONS_ERROR; 334 } 335 336 /* Create a new child */ 337 if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) { 338 return LDB_ERR_OPERATIONS_ERROR; 339 } 340 341 /* And replace it with CN=foo (we need the attribute in upper case */ 342 return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, 343 *ldb_dn_get_rdn_val(newdn)); 344} 345 346/* Fix all attribute names to be in the correct case, and check they are all valid per the schema */ 347static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg) 348{ 349 int i; 350 for (i=0; i < msg->num_elements; i++) { 351 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name); 352 /* Add in a very special case for 'clearTextPassword', 353 * which is used for internal processing only, and is 354 * not presented in the schema */ 355 if (!attribute) { 356 if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) { 357 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name); 358 return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE; 359 } 360 } else { 361 msg->elements[i].name = attribute->lDAPDisplayName; 362 } 363 } 364 365 return LDB_SUCCESS; 366} 367 368static int objectclass_do_add(struct oc_context *ac); 369 370static int objectclass_add(struct ldb_module *module, struct ldb_request *req) 371{ 372 struct ldb_context *ldb; 373 struct ldb_request *search_req; 374 struct oc_context *ac; 375 struct ldb_dn *parent_dn; 376 int ret; 377 static const char * const parent_attrs[] = { "objectGUID", NULL }; 378 379 ldb = ldb_module_get_ctx(module); 380 381 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n"); 382 383 /* do not manipulate our control entries */ 384 if (ldb_dn_is_special(req->op.add.message->dn)) { 385 return ldb_next_request(module, req); 386 } 387 388 /* the objectClass must be specified on add */ 389 if (ldb_msg_find_element(req->op.add.message, 390 "objectClass") == NULL) { 391 return LDB_ERR_OBJECT_CLASS_VIOLATION; 392 } 393 394 ac = oc_init_context(module, req); 395 if (ac == NULL) { 396 return LDB_ERR_OPERATIONS_ERROR; 397 } 398 399 /* If there isn't a parent, just go on to the add processing */ 400 if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) { 401 return objectclass_do_add(ac); 402 } 403 404 /* get copy of parent DN */ 405 parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn); 406 if (parent_dn == NULL) { 407 ldb_oom(ldb); 408 return LDB_ERR_OPERATIONS_ERROR; 409 } 410 411 ret = ldb_build_search_req(&search_req, ldb, 412 ac, parent_dn, LDB_SCOPE_BASE, 413 "(objectClass=*)", parent_attrs, 414 NULL, 415 ac, get_search_callback, 416 req); 417 if (ret != LDB_SUCCESS) { 418 return ret; 419 } 420 talloc_steal(search_req, parent_dn); 421 422 ac->step_fn = objectclass_do_add; 423 424 return ldb_next_request(ac->module, search_req); 425} 426 427static int objectclass_do_add(struct oc_context *ac) 428{ 429 struct ldb_context *ldb; 430 const struct dsdb_schema *schema; 431 struct ldb_request *add_req; 432 char *value; 433 struct ldb_message_element *objectclass_element; 434 struct ldb_message *msg; 435 TALLOC_CTX *mem_ctx; 436 struct class_list *sorted, *current; 437 int ret; 438 439 ldb = ldb_module_get_ctx(ac->module); 440 schema = dsdb_get_schema(ldb); 441 442 mem_ctx = talloc_new(ac); 443 if (mem_ctx == NULL) { 444 return LDB_ERR_OPERATIONS_ERROR; 445 } 446 447 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message); 448 449 /* Check we have a valid parent */ 450 if (ac->search_res == NULL) { 451 if (ldb_dn_compare(ldb_get_root_basedn(ldb), 452 msg->dn) == 0) { 453 /* Allow the tree to be started */ 454 455 /* but don't keep any error string, it's meaningless */ 456 ldb_set_errstring(ldb, NULL); 457 } else { 458 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 459 ldb_dn_get_linearized(msg->dn)); 460 talloc_free(mem_ctx); 461 return LDB_ERR_UNWILLING_TO_PERFORM; 462 } 463 } else { 464 const struct ldb_val *parent_guid; 465 466 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */ 467 ret = fix_dn(msg, 468 ac->req->op.add.message->dn, 469 ac->search_res->message->dn, 470 &msg->dn); 471 472 if (ret != LDB_SUCCESS) { 473 ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form", 474 ldb_dn_get_linearized(ac->req->op.add.message->dn)); 475 talloc_free(mem_ctx); 476 return ret; 477 } 478 479 parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID"); 480 if (parent_guid == NULL) { 481 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not have an objectGUID!", 482 ldb_dn_get_linearized(msg->dn)); 483 talloc_free(mem_ctx); 484 return LDB_ERR_UNWILLING_TO_PERFORM; 485 } 486 487 /* TODO: Check this is a valid child to this parent, 488 * by reading the allowedChildClasses and 489 * allowedChildClasssesEffective attributes */ 490 ret = ldb_msg_add_steal_value(msg, "parentGUID", discard_const(parent_guid)); 491 if (ret != LDB_SUCCESS) { 492 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, failed to add parentGUID", 493 ldb_dn_get_linearized(msg->dn)); 494 talloc_free(mem_ctx); 495 return LDB_ERR_UNWILLING_TO_PERFORM; 496 } 497 } 498 if (schema) { 499 ret = fix_attributes(ldb, schema, msg); 500 if (ret != LDB_SUCCESS) { 501 talloc_free(mem_ctx); 502 return ret; 503 } 504 505 /* This is now the objectClass list from the database */ 506 objectclass_element = ldb_msg_find_element(msg, "objectClass"); 507 508 if (!objectclass_element) { 509 /* Where did it go? bail now... */ 510 talloc_free(mem_ctx); 511 return LDB_ERR_OPERATIONS_ERROR; 512 } 513 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted); 514 if (ret != LDB_SUCCESS) { 515 talloc_free(mem_ctx); 516 return ret; 517 } 518 519 ldb_msg_remove_attr(msg, "objectClass"); 520 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL); 521 522 if (ret != LDB_SUCCESS) { 523 talloc_free(mem_ctx); 524 return ret; 525 } 526 527 /* We must completely replace the existing objectClass entry, 528 * because we need it sorted */ 529 530 /* Move from the linked list back into an ldb msg */ 531 for (current = sorted; current; current = current->next) { 532 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName); 533 if (value == NULL) { 534 ldb_oom(ldb); 535 talloc_free(mem_ctx); 536 return LDB_ERR_OPERATIONS_ERROR; 537 } 538 ret = ldb_msg_add_string(msg, "objectClass", value); 539 if (ret != LDB_SUCCESS) { 540 ldb_set_errstring(ldb, 541 "objectclass: could not re-add sorted " 542 "objectclass to modify msg"); 543 talloc_free(mem_ctx); 544 return ret; 545 } 546 /* Last one is the critical one */ 547 if (!current->next) { 548 struct ldb_message_element *el; 549 int32_t systemFlags = 0; 550 DATA_BLOB *sd; 551 if (!ldb_msg_find_element(msg, "objectCategory")) { 552 value = talloc_strdup(msg, current->objectclass->defaultObjectCategory); 553 if (value == NULL) { 554 ldb_oom(ldb); 555 talloc_free(mem_ctx); 556 return LDB_ERR_OPERATIONS_ERROR; 557 } 558 ldb_msg_add_string(msg, "objectCategory", value); 559 } 560 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) { 561 ldb_msg_add_string(msg, "showInAdvancedViewOnly", 562 "TRUE"); 563 } 564 565 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */ 566 el = ldb_msg_find_element(msg, "systemFlags"); 567 568 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0); 569 570 if (el) { 571 /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */ 572 /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */ 573 ldb_msg_remove_element(msg, el); 574 } 575 576 /* This flag is only allowed on attributeSchema objects */ 577 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) { 578 systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN; 579 } 580 581 if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "server") == 0) { 582 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE); 583 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "site") == 0 584 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "serverContainer") == 0 585 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) { 586 systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE); 587 588 } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0 589 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0 590 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) { 591 systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME); 592 } 593 594 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */ 595 596 if (el || systemFlags != 0) { 597 samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags); 598 } 599 } 600 } 601 } 602 603 talloc_free(mem_ctx); 604 ret = ldb_msg_sanity_check(ldb, msg); 605 606 607 if (ret != LDB_SUCCESS) { 608 return ret; 609 } 610 611 ret = ldb_build_add_req(&add_req, ldb, ac, 612 msg, 613 ac->req->controls, 614 ac, oc_op_callback, 615 ac->req); 616 if (ret != LDB_SUCCESS) { 617 return ret; 618 } 619 620 /* perform the add */ 621 return ldb_next_request(ac->module, add_req); 622} 623 624static int oc_modify_callback(struct ldb_request *req, 625 struct ldb_reply *ares); 626static int objectclass_do_mod(struct oc_context *ac); 627 628static int objectclass_modify(struct ldb_module *module, struct ldb_request *req) 629{ 630 struct ldb_context *ldb = ldb_module_get_ctx(module); 631 struct ldb_message_element *objectclass_element; 632 struct ldb_message *msg; 633 const struct dsdb_schema *schema = dsdb_get_schema(ldb); 634 struct class_list *sorted, *current; 635 struct ldb_request *down_req; 636 struct oc_context *ac; 637 TALLOC_CTX *mem_ctx; 638 char *value; 639 int ret; 640 641 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n"); 642 643 /* do not manipulate our control entries */ 644 if (ldb_dn_is_special(req->op.mod.message->dn)) { 645 return ldb_next_request(module, req); 646 } 647 648 /* Without schema, there isn't much to do here */ 649 if (!schema) { 650 return ldb_next_request(module, req); 651 } 652 objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass"); 653 654 ac = oc_init_context(module, req); 655 if (ac == NULL) { 656 return LDB_ERR_OPERATIONS_ERROR; 657 } 658 659 /* If no part of this touches the objectClass, then we don't 660 * need to make any changes. */ 661 662 /* If the only operation is the deletion of the objectClass 663 * then go on with just fixing the attribute case */ 664 if (!objectclass_element) { 665 msg = ldb_msg_copy_shallow(ac, req->op.mod.message); 666 if (msg == NULL) { 667 return LDB_ERR_OPERATIONS_ERROR; 668 } 669 670 ret = fix_attributes(ldb, schema, msg); 671 if (ret != LDB_SUCCESS) { 672 return ret; 673 } 674 675 ret = ldb_build_mod_req(&down_req, ldb, ac, 676 msg, 677 req->controls, 678 ac, oc_op_callback, 679 req); 680 if (ret != LDB_SUCCESS) { 681 return ret; 682 } 683 684 /* go on with the call chain */ 685 return ldb_next_request(module, down_req); 686 } 687 688 switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) { 689 case LDB_FLAG_MOD_DELETE: 690 if (objectclass_element->num_values == 0) { 691 return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED; 692 } 693 break; 694 695 case LDB_FLAG_MOD_REPLACE: 696 mem_ctx = talloc_new(ac); 697 if (mem_ctx == NULL) { 698 return LDB_ERR_OPERATIONS_ERROR; 699 } 700 701 msg = ldb_msg_copy_shallow(ac, req->op.mod.message); 702 if (msg == NULL) { 703 talloc_free(mem_ctx); 704 return LDB_ERR_OPERATIONS_ERROR; 705 } 706 707 ret = fix_attributes(ldb, schema, msg); 708 if (ret != LDB_SUCCESS) { 709 talloc_free(mem_ctx); 710 return ret; 711 } 712 713 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted); 714 if (ret != LDB_SUCCESS) { 715 talloc_free(mem_ctx); 716 return ret; 717 } 718 719 /* We must completely replace the existing objectClass entry, 720 * because we need it sorted */ 721 722 ldb_msg_remove_attr(msg, "objectClass"); 723 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL); 724 725 if (ret != LDB_SUCCESS) { 726 talloc_free(mem_ctx); 727 return ret; 728 } 729 730 /* Move from the linked list back into an ldb msg */ 731 for (current = sorted; current; current = current->next) { 732 /* copy the value as this string is on the schema 733 * context and we can't rely on it not changing 734 * before the operation is over */ 735 value = talloc_strdup(msg, 736 current->objectclass->lDAPDisplayName); 737 if (value == NULL) { 738 ldb_oom(ldb); 739 talloc_free(mem_ctx); 740 return LDB_ERR_OPERATIONS_ERROR; 741 } 742 ret = ldb_msg_add_string(msg, "objectClass", value); 743 if (ret != LDB_SUCCESS) { 744 ldb_set_errstring(ldb, 745 "objectclass: could not re-add sorted " 746 "objectclass to modify msg"); 747 talloc_free(mem_ctx); 748 return ret; 749 } 750 } 751 752 talloc_free(mem_ctx); 753 754 ret = ldb_msg_sanity_check(ldb, msg); 755 if (ret != LDB_SUCCESS) { 756 return ret; 757 } 758 759 ret = ldb_build_mod_req(&down_req, ldb, ac, 760 msg, 761 req->controls, 762 ac, oc_op_callback, 763 req); 764 if (ret != LDB_SUCCESS) { 765 return ret; 766 } 767 768 /* go on with the call chain */ 769 return ldb_next_request(module, down_req); 770 } 771 772 /* This isn't the default branch of the switch, but a 'in any 773 * other case'. When a delete isn't for all objectClasses for 774 * example 775 */ 776 777 msg = ldb_msg_copy_shallow(ac, req->op.mod.message); 778 if (msg == NULL) { 779 ldb_oom(ldb); 780 return LDB_ERR_OPERATIONS_ERROR; 781 } 782 783 ret = fix_attributes(ldb, schema, msg); 784 if (ret != LDB_SUCCESS) { 785 ldb_oom(ldb); 786 return ret; 787 } 788 789 ret = ldb_build_mod_req(&down_req, ldb, ac, 790 msg, 791 req->controls, 792 ac, oc_modify_callback, 793 req); 794 if (ret != LDB_SUCCESS) { 795 return ret; 796 } 797 798 return ldb_next_request(module, down_req); 799} 800 801static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares) 802{ 803 struct ldb_context *ldb; 804 static const char * const attrs[] = { "objectClass", NULL }; 805 struct ldb_request *search_req; 806 struct oc_context *ac; 807 int ret; 808 809 ac = talloc_get_type(req->context, struct oc_context); 810 ldb = ldb_module_get_ctx(ac->module); 811 812 if (!ares) { 813 return ldb_module_done(ac->req, NULL, NULL, 814 LDB_ERR_OPERATIONS_ERROR); 815 } 816 if (ares->error != LDB_SUCCESS) { 817 return ldb_module_done(ac->req, ares->controls, 818 ares->response, ares->error); 819 } 820 821 if (ares->type != LDB_REPLY_DONE) { 822 talloc_free(ares); 823 return ldb_module_done(ac->req, NULL, NULL, 824 LDB_ERR_OPERATIONS_ERROR); 825 } 826 827 ret = ldb_build_search_req(&search_req, ldb, ac, 828 ac->req->op.mod.message->dn, LDB_SCOPE_BASE, 829 "(objectClass=*)", 830 attrs, NULL, 831 ac, get_search_callback, 832 ac->req); 833 if (ret != LDB_SUCCESS) { 834 return ldb_module_done(ac->req, NULL, NULL, ret); 835 } 836 837 ac->step_fn = objectclass_do_mod; 838 839 ret = ldb_next_request(ac->module, search_req); 840 if (ret != LDB_SUCCESS) { 841 return ldb_module_done(ac->req, NULL, NULL, ret); 842 } 843 return LDB_SUCCESS; 844} 845 846static int objectclass_do_mod(struct oc_context *ac) 847{ 848 struct ldb_context *ldb; 849 const struct dsdb_schema *schema; 850 struct ldb_request *mod_req; 851 char *value; 852 struct ldb_message_element *objectclass_element; 853 struct ldb_message *msg; 854 TALLOC_CTX *mem_ctx; 855 struct class_list *sorted, *current; 856 int ret; 857 858 ldb = ldb_module_get_ctx(ac->module); 859 860 if (ac->search_res == NULL) { 861 return LDB_ERR_OPERATIONS_ERROR; 862 } 863 schema = dsdb_get_schema(ldb); 864 865 mem_ctx = talloc_new(ac); 866 if (mem_ctx == NULL) { 867 return LDB_ERR_OPERATIONS_ERROR; 868 } 869 870 /* use a new message structure */ 871 msg = ldb_msg_new(ac); 872 if (msg == NULL) { 873 ldb_set_errstring(ldb, 874 "objectclass: could not create new modify msg"); 875 talloc_free(mem_ctx); 876 return LDB_ERR_OPERATIONS_ERROR; 877 } 878 879 /* This is now the objectClass list from the database */ 880 objectclass_element = ldb_msg_find_element(ac->search_res->message, 881 "objectClass"); 882 if (!objectclass_element) { 883 /* Where did it go? bail now... */ 884 talloc_free(mem_ctx); 885 return LDB_ERR_OPERATIONS_ERROR; 886 } 887 888 /* modify dn */ 889 msg->dn = ac->req->op.mod.message->dn; 890 891 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted); 892 if (ret != LDB_SUCCESS) { 893 return ret; 894 } 895 896 /* We must completely replace the existing objectClass entry. 897 * We could do a constrained add/del, but we are meant to be 898 * in a transaction... */ 899 900 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL); 901 if (ret != LDB_SUCCESS) { 902 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg"); 903 talloc_free(mem_ctx); 904 return ret; 905 } 906 907 /* Move from the linked list back into an ldb msg */ 908 for (current = sorted; current; current = current->next) { 909 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName); 910 if (value == NULL) { 911 ldb_oom(ldb); 912 return LDB_ERR_OPERATIONS_ERROR; 913 } 914 ret = ldb_msg_add_string(msg, "objectClass", value); 915 if (ret != LDB_SUCCESS) { 916 ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg"); 917 talloc_free(mem_ctx); 918 return ret; 919 } 920 } 921 922 ret = ldb_msg_sanity_check(ldb, msg); 923 if (ret != LDB_SUCCESS) { 924 talloc_free(mem_ctx); 925 return ret; 926 } 927 928 ret = ldb_build_mod_req(&mod_req, ldb, ac, 929 msg, 930 ac->req->controls, 931 ac, oc_op_callback, 932 ac->req); 933 if (ret != LDB_SUCCESS) { 934 talloc_free(mem_ctx); 935 return ret; 936 } 937 938 talloc_free(mem_ctx); 939 /* perform the modify */ 940 return ldb_next_request(ac->module, mod_req); 941} 942 943static int objectclass_do_rename(struct oc_context *ac); 944 945static int objectclass_rename(struct ldb_module *module, struct ldb_request *req) 946{ 947 static const char * const attrs[] = { "objectGUID", NULL }; 948 struct ldb_context *ldb; 949 struct ldb_request *search_req; 950 struct oc_context *ac; 951 struct ldb_dn *parent_dn; 952 int ret; 953 954 ldb = ldb_module_get_ctx(module); 955 956 ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n"); 957 958 if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */ 959 return ldb_next_request(module, req); 960 } 961 962 /* Firstly ensure we are not trying to rename it to be a child of itself */ 963 if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 964 && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) { 965 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself", 966 ldb_dn_get_linearized(req->op.rename.olddn)); 967 return LDB_ERR_UNWILLING_TO_PERFORM; 968 } 969 970 ac = oc_init_context(module, req); 971 if (ac == NULL) { 972 return LDB_ERR_OPERATIONS_ERROR; 973 } 974 975 parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn); 976 if (parent_dn == NULL) { 977 ldb_oom(ldb); 978 return LDB_ERR_OPERATIONS_ERROR; 979 } 980 981 /* note that the results of this search are kept and used to 982 update the parentGUID in objectclass_rename_callback() */ 983 ret = ldb_build_search_req(&search_req, ldb, 984 ac, parent_dn, LDB_SCOPE_BASE, 985 "(objectClass=*)", 986 attrs, NULL, 987 ac, get_search_callback, 988 req); 989 if (ret != LDB_SUCCESS) { 990 return ret; 991 } 992 993 /* we have to add the show deleted control, as otherwise DRS 994 deletes will be refused as we will think the target parent 995 does not exist */ 996 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL); 997 998 if (ret != LDB_SUCCESS) { 999 return ret; 1000 } 1001 1002 ac->step_fn = objectclass_do_rename; 1003 1004 return ldb_next_request(ac->module, search_req); 1005} 1006 1007/* 1008 called after the rename happens. 1009 We now need to fix the parentGUID of the object to be the objectGUID of 1010 the new parent 1011*/ 1012static int objectclass_rename_callback(struct ldb_request *req, struct ldb_reply *ares) 1013{ 1014 struct ldb_context *ldb; 1015 struct oc_context *ac; 1016 const struct ldb_val *parent_guid; 1017 struct ldb_request *mod_req = NULL; 1018 int ret; 1019 struct ldb_message *msg; 1020 struct ldb_message_element *el = NULL; 1021 1022 ac = talloc_get_type(req->context, struct oc_context); 1023 ldb = ldb_module_get_ctx(ac->module); 1024 1025 /* make sure the rename succeeded */ 1026 if (!ares) { 1027 return ldb_module_done(ac->req, NULL, NULL, 1028 LDB_ERR_OPERATIONS_ERROR); 1029 } 1030 if (ares->error != LDB_SUCCESS) { 1031 return ldb_module_done(ac->req, ares->controls, 1032 ares->response, ares->error); 1033 } 1034 1035 1036 /* the ac->search_res should contain the new parents objectGUID */ 1037 parent_guid = ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID"); 1038 if (parent_guid == NULL) { 1039 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, new parent does not have an objectGUID!", 1040 ldb_dn_get_linearized(ac->req->op.rename.newdn)); 1041 return LDB_ERR_UNWILLING_TO_PERFORM; 1042 1043 } 1044 1045 /* construct the modify message */ 1046 msg = ldb_msg_new(ac); 1047 if (msg == NULL) { 1048 ldb_oom(ldb); 1049 return LDB_ERR_OPERATIONS_ERROR; 1050 } 1051 1052 msg->dn = ac->req->op.rename.newdn; 1053 1054 ret = ldb_msg_add_value(msg, "parentGUID", parent_guid, &el); 1055 if (ret != LDB_SUCCESS) { 1056 return ret; 1057 } 1058 1059 el->flags = LDB_FLAG_MOD_REPLACE; 1060 1061 ret = ldb_build_mod_req(&mod_req, ldb, ac, msg, 1062 NULL, ac, oc_op_callback, req); 1063 1064 return ldb_next_request(ac->module, mod_req); 1065} 1066 1067static int objectclass_do_rename(struct oc_context *ac) 1068{ 1069 struct ldb_context *ldb; 1070 struct ldb_request *rename_req; 1071 struct ldb_dn *fixed_dn; 1072 int ret; 1073 1074 ldb = ldb_module_get_ctx(ac->module); 1075 1076 /* Check we have a valid parent */ 1077 if (ac->search_res == NULL) { 1078 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!", 1079 ldb_dn_get_linearized(ac->req->op.rename.newdn)); 1080 return LDB_ERR_UNWILLING_TO_PERFORM; 1081 } 1082 1083 /* Fix up the DN to be in the standard form, 1084 * taking particular care to match the parent DN */ 1085 ret = fix_dn(ac, 1086 ac->req->op.rename.newdn, 1087 ac->search_res->message->dn, 1088 &fixed_dn); 1089 if (ret != LDB_SUCCESS) { 1090 return ret; 1091 } 1092 1093 /* TODO: Check this is a valid child to this parent, 1094 * by reading the allowedChildClasses and 1095 * allowedChildClasssesEffective attributes */ 1096 1097 ret = ldb_build_rename_req(&rename_req, ldb, ac, 1098 ac->req->op.rename.olddn, fixed_dn, 1099 ac->req->controls, 1100 ac, objectclass_rename_callback, 1101 ac->req); 1102 if (ret != LDB_SUCCESS) { 1103 return ret; 1104 } 1105 1106 /* perform the rename */ 1107 return ldb_next_request(ac->module, rename_req); 1108} 1109 1110_PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = { 1111 .name = "objectclass", 1112 .add = objectclass_add, 1113 .modify = objectclass_modify, 1114 .rename = objectclass_rename, 1115}; 1116