root/source4/dsdb/samdb/ldb_modules/objectclass.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. oc_init_context
  2. objectclass_sort
  3. get_sd
  4. get_search_callback
  5. oc_op_callback
  6. fix_dn
  7. fix_attributes
  8. objectclass_add
  9. objectclass_do_add
  10. objectclass_modify
  11. oc_modify_callback
  12. objectclass_do_mod
  13. objectclass_rename
  14. objectclass_do_rename

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

/* [<][>][^][v][top][bottom][index][help] */