root/source3/lib/ldb/modules/objectclass.c

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

DEFINITIONS

This source file includes following definitions.
  1. oc_init_handle
  2. objectclass_sort
  3. objectclass_add
  4. objectclass_modify
  5. get_self_callback
  6. objectclass_search_self
  7. objectclass_do_mod
  8. oc_wait
  9. oc_wait_all
  10. objectclass_wait
  11. ldb_objectclass_init

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Simo Sorce  2006
   5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
   6 
   7      ** NOTE! The following LGPL license applies to the ldb
   8      ** library. This does NOT imply that all of Samba is released
   9      ** under the LGPL
  10    
  11    This library is free software; you can redistribute it and/or
  12    modify it under the terms of the GNU Lesser General Public
  13    License as published by the Free Software Foundation; either
  14    version 3 of the License, or (at your option) any later version.
  15 
  16    This library is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19    Lesser General Public License for more details.
  20 
  21    You should have received a copy of the GNU Lesser General Public
  22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 /*
  26  *  Name: ldb
  27  *
  28  *  Component: objectClass sorting module
  29  *
  30  *  Description: sort the objectClass attribute into the class hierarchy
  31  *
  32  *  Author: Andrew Bartlett
  33  */
  34 
  35 #include "includes.h"
  36 #include "ldb/include/includes.h"
  37 
  38 struct oc_context {
  39 
  40         enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step;
  41 
  42         struct ldb_module *module;
  43         struct ldb_request *orig_req;
  44 
  45         struct ldb_request *down_req;
  46 
  47         struct ldb_request *search_req;
  48         struct ldb_reply *search_res;
  49 
  50         struct ldb_request *mod_req;
  51 };
  52 
  53 struct class_list {
  54         struct class_list *prev, *next;
  55         const char *objectclass;
  56 };
  57 
  58 static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
  59 {
  60         struct oc_context *ac;
  61         struct ldb_handle *h;
  62 
  63         h = talloc_zero(req, struct ldb_handle);
  64         if (h == NULL) {
  65                 ldb_set_errstring(module->ldb, "Out of Memory");
  66                 return NULL;
  67         }
  68 
  69         h->module = module;
  70 
  71         ac = talloc_zero(h, struct oc_context);
  72         if (ac == NULL) {
  73                 ldb_set_errstring(module->ldb, "Out of Memory");
  74                 talloc_free(h);
  75                 return NULL;
  76         }
  77 
  78         h->private_data = (void *)ac;
  79 
  80         h->state = LDB_ASYNC_INIT;
  81         h->status = LDB_SUCCESS;
  82 
  83         ac->module = module;
  84         ac->orig_req = req;
  85 
  86         return h;
  87 }
  88 
  89 static int objectclass_sort(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
  90                             TALLOC_CTX *mem_ctx,
  91                             struct ldb_message_element *objectclass_element,
  92                             struct class_list **sorted_out) 
  93 {
  94         int i;
  95         int layer;
  96         struct class_list *sorted = NULL, *parent_class = NULL,
  97                 *subclass = NULL, *unsorted = NULL, *current, *poss_subclass;
  98         /* DESIGN:
  99          *
 100          * We work on 4 different 'bins' (implemented here as linked lists):
 101          *
 102          * * sorted:       the eventual list, in the order we wish to push
 103          *                 into the database.  This is the only ordered list.
 104          *
 105          * * parent_class: The current parent class 'bin' we are
 106          *                 trying to find subclasses for
 107          *
 108          * * subclass:     The subclasses we have found so far
 109          *
 110          * * unsorted:     The remaining objectClasses
 111          *
 112          * The process is a matter of filtering objectClasses up from
 113          * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
 114          * 
 115          * We start with 'top' (found and promoted to parent_class
 116          * initially).  Then we find (in unsorted) all the direct
 117          * subclasses of 'top'.  parent_classes is concatenated onto
 118          * the end of 'sorted', and subclass becomes the list in
 119          * parent_class.
 120          *
 121          * We then repeat, until we find no more subclasses.  Any left
 122          * over classes are added to the end.
 123          *
 124          */
 125 
 126         /* Firstly, dump all the objectClass elements into the
 127          * unsorted bin, except for 'top', which is special */
 128         for (i=0; i < objectclass_element->num_values; i++) {
 129                 current = talloc(mem_ctx, struct class_list);
 130                 if (!current) {
 131                         ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list");
 132                         talloc_free(mem_ctx);
 133                         return LDB_ERR_OPERATIONS_ERROR;
 134                 }
 135                 current->objectclass = (const char *)objectclass_element->values[i].data;
 136 
 137                 /* this is the root of the tree.  We will start
 138                  * looking for subclasses from here */
 139                 if (ldb_attr_cmp("top", current->objectclass) == 0) {
 140                         DLIST_ADD(parent_class, current);
 141                 } else {
 142                         DLIST_ADD(unsorted, current);
 143                 }
 144         }
 145 
 146         /* DEBUGGING aid:  how many layers are we down now? */
 147         layer = 0;
 148         do {
 149                 layer++;
 150                 /* Find all the subclasses of classes in the
 151                  * parent_classes.  Push them onto the subclass list */
 152 
 153                 /* Ensure we don't bother if there are no unsorted entries left */
 154                 for (current = parent_class; unsorted && current; current = current->next) {
 155                         const char **subclasses = ldb_subclass_list(module->ldb, current->objectclass);
 156 
 157                         /* Walk the list of possible subclasses in unsorted */
 158                         for (poss_subclass = unsorted; poss_subclass; ) {
 159                                 struct class_list *next;
 160                                 
 161                                 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
 162                                 next = poss_subclass->next;
 163 
 164                                 for (i = 0; subclasses && subclasses[i]; i++) {
 165                                         if (ldb_attr_cmp(poss_subclass->objectclass, subclasses[i]) == 0) {
 166                                                 DLIST_REMOVE(unsorted, poss_subclass);
 167                                                 DLIST_ADD(subclass, poss_subclass);
 168 
 169                                                 break;
 170                                         }
 171                                 }
 172                                 poss_subclass = next;
 173                         }
 174                 }
 175 
 176                 /* Now push the parent_classes as sorted, we are done with
 177                 these.  Add to the END of the list by concatenation */
 178                 DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
 179 
 180                 /* and now find subclasses of these */
 181                 parent_class = subclass;
 182                 subclass = NULL;
 183 
 184                 /* If we didn't find any subclasses we will fall out
 185                  * the bottom here */
 186         } while (parent_class);
 187 
 188         /* This shouldn't happen, and would break MMC, but we can't
 189          * afford to loose objectClasses.  Perhaps there was no 'top',
 190          * or some other schema error? 
 191          *
 192          * Detecting schema errors is the job of the schema module, so
 193          * at this layer we just try not to loose data
 194          */
 195         DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
 196 
 197         *sorted_out = sorted;
 198         return LDB_SUCCESS;
 199 }
 200 
 201 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 202 {
 203         struct ldb_message_element *objectclass_element;
 204         struct class_list *sorted, *current;
 205         struct ldb_request *down_req;
 206         struct ldb_message *msg;
 207         int ret;
 208         TALLOC_CTX *mem_ctx;
 209 
 210         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
 211 
 212         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
 213                 return ldb_next_request(module, req);
 214         }
 215         
 216         objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass");
 217 
 218         /* If no part of this add has an objectClass, then we don't
 219          * need to make any changes. cn=rootdse doesn't have an objectClass */
 220         if (!objectclass_element) {
 221                 return ldb_next_request(module, req);
 222         }
 223 
 224         mem_ctx = talloc_new(req);
 225         if (mem_ctx == NULL) {
 226                 return LDB_ERR_OPERATIONS_ERROR;
 227         }
 228 
 229         ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
 230         if (ret != LDB_SUCCESS) {
 231                 return ret;
 232         }
 233 
 234         /* prepare the first operation */
 235         down_req = talloc(req, struct ldb_request);
 236         if (down_req == NULL) {
 237                 ldb_set_errstring(module->ldb, "Out of memory!");
 238                 talloc_free(mem_ctx);
 239                 return LDB_ERR_OPERATIONS_ERROR;
 240         }
 241 
 242         *down_req = *req; /* copy the request */
 243 
 244         down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
 245 
 246         if (down_req->op.add.message == NULL) {
 247                 talloc_free(mem_ctx);
 248                 return LDB_ERR_OPERATIONS_ERROR;
 249         }
 250 
 251         ldb_msg_remove_attr(msg, "objectClass");
 252         ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
 253         
 254         if (ret != LDB_SUCCESS) {
 255                 talloc_free(mem_ctx);
 256                 return ret;
 257         }
 258 
 259         /* We must completely replace the existing objectClass entry,
 260          * because we need it sorted */
 261 
 262         /* Move from the linked list back into an ldb msg */
 263         for (current = sorted; current; current = current->next) {
 264                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
 265                 if (ret != LDB_SUCCESS) {
 266                         ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
 267                         talloc_free(mem_ctx);
 268                         return ret;
 269                 }
 270         }
 271 
 272         talloc_free(mem_ctx);
 273         ret = ldb_msg_sanity_check(module->ldb, msg);
 274 
 275         if (ret != LDB_SUCCESS) {
 276                 return ret;
 277         }
 278 
 279         /* go on with the call chain */
 280         ret = ldb_next_request(module, down_req);
 281 
 282         /* do not free down_req as the call results may be linked to it,
 283          * it will be freed when the upper level request get freed */
 284         if (ret == LDB_SUCCESS) {
 285                 req->handle = down_req->handle;
 286         }
 287         return ret;
 288 }
 289 
 290 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 291 {
 292         struct ldb_message_element *objectclass_element;
 293         struct ldb_message *msg;
 294         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
 295 
 296         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
 297                 return ldb_next_request(module, req);
 298         }
 299         
 300         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
 301 
 302         /* If no part of this touches the objectClass, then we don't
 303          * need to make any changes.  */
 304         /* If the only operation is the deletion of the objectClass then go on */
 305         if (!objectclass_element) {
 306                 return ldb_next_request(module, req);
 307         }
 308 
 309         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
 310         case LDB_FLAG_MOD_DELETE:
 311                 /* Delete everything?  Probably totally illigal, but hey! */
 312                 if (objectclass_element->num_values == 0) {
 313                         return ldb_next_request(module, req);
 314                 }
 315                 break;
 316         case LDB_FLAG_MOD_REPLACE:
 317         {
 318                 struct ldb_request *down_req;
 319                 struct class_list *sorted, *current;
 320                 TALLOC_CTX *mem_ctx;
 321                 int ret;
 322                 mem_ctx = talloc_new(req);
 323                 if (mem_ctx == NULL) {
 324                         return LDB_ERR_OPERATIONS_ERROR;
 325                 }
 326 
 327                 /* prepare the first operation */
 328                 down_req = talloc(req, struct ldb_request);
 329                 if (down_req == NULL) {
 330                         ldb_set_errstring(module->ldb, "Out of memory!");
 331                         talloc_free(mem_ctx);
 332                         return LDB_ERR_OPERATIONS_ERROR;
 333                 }
 334                 
 335                 *down_req = *req; /* copy the request */
 336                 
 337                 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
 338                 
 339                 if (down_req->op.add.message == NULL) {
 340                         talloc_free(mem_ctx);
 341                         return LDB_ERR_OPERATIONS_ERROR;
 342                 }
 343                 
 344                 ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
 345                 if (ret != LDB_SUCCESS) {
 346                         return ret;
 347                 }
 348 
 349                 /* We must completely replace the existing objectClass entry,
 350                  * because we need it sorted */
 351                 
 352                 ldb_msg_remove_attr(msg, "objectClass");
 353                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
 354                 
 355                 if (ret != LDB_SUCCESS) {
 356                         talloc_free(mem_ctx);
 357                         return ret;
 358                 }
 359 
 360                 /* Move from the linked list back into an ldb msg */
 361                 for (current = sorted; current; current = current->next) {
 362                         ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
 363                         if (ret != LDB_SUCCESS) {
 364                                 ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
 365                                 talloc_free(mem_ctx);
 366                                 return ret;
 367                         }
 368                 }
 369                 
 370                 talloc_free(mem_ctx);
 371 
 372                 ret = ldb_msg_sanity_check(module->ldb, msg);
 373                 if (ret != LDB_SUCCESS) {
 374                         talloc_free(mem_ctx);
 375                         return ret;
 376                 }
 377                 
 378                 /* go on with the call chain */
 379                 ret = ldb_next_request(module, down_req);
 380                 
 381                 /* do not free down_req as the call results may be linked to it,
 382                  * it will be freed when the upper level request get freed */
 383                 if (ret == LDB_SUCCESS) {
 384                         req->handle = down_req->handle;
 385                 }
 386                 return ret;
 387         }
 388         }
 389 
 390         {
 391                 struct ldb_handle *h;
 392                 struct oc_context *ac;
 393                 
 394                 h = oc_init_handle(req, module);
 395                 if (!h) {
 396                         return LDB_ERR_OPERATIONS_ERROR;
 397                 }
 398                 ac = talloc_get_type(h->private_data, struct oc_context);
 399                 
 400                 /* return or own handle to deal with this call */
 401                 req->handle = h;
 402                 
 403                 /* prepare the first operation */
 404                 ac->down_req = talloc(ac, struct ldb_request);
 405                 if (ac->down_req == NULL) {
 406                         ldb_set_errstring(module->ldb, "Out of memory!");
 407                         return LDB_ERR_OPERATIONS_ERROR;
 408                 }
 409                 
 410                 *(ac->down_req) = *req; /* copy the request */
 411                 
 412                 ac->down_req->context = NULL;
 413                 ac->down_req->callback = NULL;
 414                 ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
 415                 
 416                 ac->step = OC_DO_REQ;
 417 
 418                 return ldb_next_request(module, ac->down_req);
 419         }
 420 }
 421 
 422 static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
     /* [<][>][^][v][top][bottom][index][help] */
 423 {
 424         struct oc_context *ac;
 425 
 426         if (!context || !ares) {
 427                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
 428                 return LDB_ERR_OPERATIONS_ERROR;
 429         }
 430 
 431         ac = talloc_get_type(context, struct oc_context);
 432 
 433         /* we are interested only in the single reply (base search) we receive here */
 434         if (ares->type == LDB_REPLY_ENTRY) {
 435                 if (ac->search_res != NULL) {
 436                         ldb_set_errstring(ldb, "Too many results");
 437                         talloc_free(ares);
 438                         return LDB_ERR_OPERATIONS_ERROR;
 439                 }
 440 
 441                 ac->search_res = talloc_move(ac, &ares);
 442         } else {
 443                 talloc_free(ares);
 444         }
 445 
 446         return LDB_SUCCESS;
 447 }
 448 
 449 static int objectclass_search_self(struct ldb_handle *h) {
     /* [<][>][^][v][top][bottom][index][help] */
 450 
 451         struct oc_context *ac;
 452         static const char * const attrs[] = { "objectClass", NULL };
 453 
 454         ac = talloc_get_type(h->private_data, struct oc_context);
 455 
 456         /* prepare the search operation */
 457         ac->search_req = talloc_zero(ac, struct ldb_request);
 458         if (ac->search_req == NULL) {
 459                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
 460                 return LDB_ERR_OPERATIONS_ERROR;
 461         }
 462 
 463         ac->search_req->operation = LDB_SEARCH;
 464         ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
 465         ac->search_req->op.search.scope = LDB_SCOPE_BASE;
 466         ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL);
 467         if (ac->search_req->op.search.tree == NULL) {
 468                 ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search");
 469                 return LDB_ERR_OPERATIONS_ERROR;
 470         }
 471         ac->search_req->op.search.attrs = attrs;
 472         ac->search_req->controls = NULL;
 473         ac->search_req->context = ac;
 474         ac->search_req->callback = get_self_callback;
 475         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
 476 
 477         ac->step = OC_SEARCH_SELF;
 478 
 479         return ldb_next_request(ac->module, ac->search_req);
 480 }
 481 
 482 static int objectclass_do_mod(struct ldb_handle *h) {
     /* [<][>][^][v][top][bottom][index][help] */
 483 
 484         struct oc_context *ac;
 485         struct ldb_message_element *objectclass_element;
 486         struct ldb_message *msg;
 487         TALLOC_CTX *mem_ctx;
 488         struct class_list *sorted, *current;
 489         int ret;
 490       
 491         ac = talloc_get_type(h->private_data, struct oc_context);
 492 
 493         mem_ctx = talloc_new(ac);
 494         if (mem_ctx == NULL) {
 495                 return LDB_ERR_OPERATIONS_ERROR;
 496         }
 497 
 498         ac->mod_req = talloc(ac, struct ldb_request);
 499         if (ac->mod_req == NULL) {
 500                 talloc_free(mem_ctx);
 501                 return LDB_ERR_OPERATIONS_ERROR;
 502         }
 503 
 504         ac->mod_req->operation = LDB_MODIFY;
 505         ac->mod_req->controls = NULL;
 506         ac->mod_req->context = ac;
 507         ac->mod_req->callback = NULL;
 508         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
 509         
 510         /* use a new message structure */
 511         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
 512         if (msg == NULL) {
 513                 ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
 514                 talloc_free(mem_ctx);
 515                 return LDB_ERR_OPERATIONS_ERROR;
 516         }
 517 
 518         /* This is now the objectClass list from the database */
 519         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
 520                                                    "objectClass");
 521         if (!objectclass_element) {
 522                 /* Where did it go?  Move along now, nothing to see here */
 523                 talloc_free(mem_ctx);
 524                 return LDB_SUCCESS;
 525         }
 526         
 527         /* modify dn */
 528         msg->dn = ac->orig_req->op.mod.message->dn;
 529 
 530         ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted);
 531         if (ret != LDB_SUCCESS) {
 532                 return ret;
 533         }
 534 
 535         /* We must completely replace the existing objectClass entry.
 536          * We could do a constrained add/del, but we are meant to be
 537          * in a transaction... */
 538 
 539         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
 540         if (ret != LDB_SUCCESS) {
 541                 ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
 542                 talloc_free(mem_ctx);
 543                 return ret;
 544         }
 545         
 546         /* Move from the linked list back into an ldb msg */
 547         for (current = sorted; current; current = current->next) {
 548                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
 549                 if (ret != LDB_SUCCESS) {
 550                         ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
 551                         talloc_free(mem_ctx);
 552                         return ret;
 553                 }
 554         }
 555 
 556         ret = ldb_msg_sanity_check(ac->module->ldb, msg);
 557         if (ret != LDB_SUCCESS) {
 558                 talloc_free(mem_ctx);
 559                 return ret;
 560         }
 561 
 562 
 563         h->state = LDB_ASYNC_INIT;
 564         h->status = LDB_SUCCESS;
 565 
 566         ac->step = OC_DO_MOD;
 567 
 568         talloc_free(mem_ctx);
 569         /* perform the search */
 570         return ldb_next_request(ac->module, ac->mod_req);
 571 }
 572 
 573 static int oc_wait(struct ldb_handle *handle) {
     /* [<][>][^][v][top][bottom][index][help] */
 574         struct oc_context *ac;
 575         int ret;
 576     
 577         if (!handle || !handle->private_data) {
 578                 return LDB_ERR_OPERATIONS_ERROR;
 579         }
 580 
 581         if (handle->state == LDB_ASYNC_DONE) {
 582                 return handle->status;
 583         }
 584 
 585         handle->state = LDB_ASYNC_PENDING;
 586         handle->status = LDB_SUCCESS;
 587 
 588         ac = talloc_get_type(handle->private_data, struct oc_context);
 589 
 590         switch (ac->step) {
 591         case OC_DO_REQ:
 592                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
 593 
 594                 if (ret != LDB_SUCCESS) {
 595                         handle->status = ret;
 596                         goto done;
 597                 }
 598                 if (ac->down_req->handle->status != LDB_SUCCESS) {
 599                         handle->status = ac->down_req->handle->status;
 600                         goto done;
 601                 }
 602 
 603                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
 604                         return LDB_SUCCESS;
 605                 }
 606 
 607                 /* mods done, go on */
 608                 return objectclass_search_self(handle);
 609 
 610         case OC_SEARCH_SELF:
 611                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
 612 
 613                 if (ret != LDB_SUCCESS) {
 614                         handle->status = ret;
 615                         goto done;
 616                 }
 617                 if (ac->search_req->handle->status != LDB_SUCCESS) {
 618                         handle->status = ac->search_req->handle->status;
 619                         goto done;
 620                 }
 621 
 622                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
 623                         return LDB_SUCCESS;
 624                 }
 625 
 626                 /* self search done, go on */
 627                 return objectclass_do_mod(handle);
 628 
 629         case OC_DO_MOD:
 630                 ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
 631 
 632                 if (ret != LDB_SUCCESS) {
 633                         handle->status = ret;
 634                         goto done;
 635                 }
 636                 if (ac->mod_req->handle->status != LDB_SUCCESS) {
 637                         handle->status = ac->mod_req->handle->status;
 638                         goto done;
 639                 }
 640 
 641                 if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
 642                         return LDB_SUCCESS;
 643                 }
 644 
 645                 break;
 646                 
 647         default:
 648                 ret = LDB_ERR_OPERATIONS_ERROR;
 649                 goto done;
 650         }
 651 
 652         ret = LDB_SUCCESS;
 653 
 654 done:
 655         handle->state = LDB_ASYNC_DONE;
 656         return ret;
 657 }
 658 
 659 static int oc_wait_all(struct ldb_handle *handle) {
     /* [<][>][^][v][top][bottom][index][help] */
 660 
 661         int ret;
 662 
 663         while (handle->state != LDB_ASYNC_DONE) {
 664                 ret = oc_wait(handle);
 665                 if (ret != LDB_SUCCESS) {
 666                         return ret;
 667                 }
 668         }
 669 
 670         return handle->status;
 671 }
 672 
 673 static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
     /* [<][>][^][v][top][bottom][index][help] */
 674 {
 675         if (type == LDB_WAIT_ALL) {
 676                 return oc_wait_all(handle);
 677         } else {
 678                 return oc_wait(handle);
 679         }
 680 }
 681 
 682 static const struct ldb_module_ops objectclass_ops = {
 683         .name              = "objectclass",
 684         .add           = objectclass_add,
 685         .modify        = objectclass_modify,
 686         .wait          = objectclass_wait
 687 };
 688 
 689 int ldb_objectclass_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 690 {
 691         return ldb_register_module(&objectclass_ops);
 692 }
 693 

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