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