r24263: Fix bug 4846 (unable to copy users in MMC Active Directory Users and
[samba.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 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 = sddl_decode(mem_ctx, 
212                                                      objectclass->defaultSecurityDescriptor,
213                                                      samdb_domain_sid(module->ldb));
214         if (!session_info || !session_info->security_token) {
215                 return NULL;
216         }
217         
218         sd->owner_sid = session_info->security_token->user_sid;
219         sd->group_sid = session_info->security_token->group_sid;
220         
221         linear_sd = talloc(mem_ctx, DATA_BLOB);
222         if (!linear_sd) {
223                 return NULL;
224         }
225
226         status = ndr_push_struct_blob(linear_sd, mem_ctx, sd, 
227                                       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
228
229         if (!NT_STATUS_IS_OK(status)) {
230                 return NULL;
231         }
232         
233         return linear_sd;
234
235 }
236
237 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
238 {
239         struct ldb_message_element *objectclass_element;
240         const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
241         struct class_list *sorted, *current;
242         struct ldb_request *down_req;
243         struct ldb_message *msg;
244         int ret;
245         TALLOC_CTX *mem_ctx;
246
247         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
248
249         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
250                 return ldb_next_request(module, req);
251         }
252         
253         objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass");
254
255         /* If no part of this add has an objectClass, then we don't
256          * need to make any changes. cn=rootdse doesn't have an objectClass */
257         if (!objectclass_element) {
258                 return ldb_next_request(module, req);
259         }
260
261         mem_ctx = talloc_new(req);
262         if (mem_ctx == NULL) {
263                 return LDB_ERR_OPERATIONS_ERROR;
264         }
265
266         ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
267         if (ret != LDB_SUCCESS) {
268                 return ret;
269         }
270
271         /* prepare the first operation */
272         down_req = talloc(req, struct ldb_request);
273         if (down_req == NULL) {
274                 ldb_set_errstring(module->ldb, "Out of memory!");
275                 talloc_free(mem_ctx);
276                 return LDB_ERR_OPERATIONS_ERROR;
277         }
278
279         *down_req = *req; /* copy the request */
280
281         down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
282
283         if (down_req->op.add.message == NULL) {
284                 talloc_free(mem_ctx);
285                 return LDB_ERR_OPERATIONS_ERROR;
286         }
287
288         ldb_msg_remove_attr(msg, "objectClass");
289         ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
290         
291         if (ret != LDB_SUCCESS) {
292                 talloc_free(mem_ctx);
293                 return ret;
294         }
295
296         /* We must completely replace the existing objectClass entry,
297          * because we need it sorted */
298
299         /* Move from the linked list back into an ldb msg */
300         for (current = sorted; current; current = current->next) {
301                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
302                 if (ret != LDB_SUCCESS) {
303                         ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
304                         talloc_free(mem_ctx);
305                         return ret;
306                 }
307                 /* Last one is the critical one */
308                 if (schema && !current->next) {
309                         const struct dsdb_class *objectclass
310                                 = dsdb_class_by_lDAPDisplayName(schema, current->objectclass);
311                         if (objectclass) {
312                                 if (!ldb_msg_find_element(msg, "objectCategory")) {
313                                         ldb_msg_add_string(msg, "objectCategory", objectclass->defaultObjectCategory);
314                                 }
315                                 if (!ldb_msg_find_element(msg, "ntSecurityDescriptor")) {
316                                         DATA_BLOB *sd = get_sd(module, mem_ctx, objectclass);
317                                         ldb_msg_add_steal_value(msg, "ntSecurityDescriptor", sd);
318                                 }
319                         }
320                 }
321         }
322
323         talloc_free(mem_ctx);
324         ret = ldb_msg_sanity_check(module->ldb, msg);
325
326         if (ret != LDB_SUCCESS) {
327                 return ret;
328         }
329
330         /* go on with the call chain */
331         ret = ldb_next_request(module, down_req);
332
333         /* do not free down_req as the call results may be linked to it,
334          * it will be freed when the upper level request get freed */
335         if (ret == LDB_SUCCESS) {
336                 req->handle = down_req->handle;
337         }
338         return ret;
339 }
340
341 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
342 {
343         struct ldb_message_element *objectclass_element;
344         struct ldb_message *msg;
345         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
346
347         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
348                 return ldb_next_request(module, req);
349         }
350         
351         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
352
353         /* If no part of this touches the objectClass, then we don't
354          * need to make any changes.  */
355         /* If the only operation is the deletion of the objectClass then go on */
356         if (!objectclass_element) {
357                 return ldb_next_request(module, req);
358         }
359
360         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
361         case LDB_FLAG_MOD_DELETE:
362                 /* Delete everything?  Probably totally illigal, but hey! */
363                 if (objectclass_element->num_values == 0) {
364                         return ldb_next_request(module, req);
365                 }
366                 break;
367         case LDB_FLAG_MOD_REPLACE:
368         {
369                 struct ldb_request *down_req;
370                 struct class_list *sorted, *current;
371                 TALLOC_CTX *mem_ctx;
372                 int ret;
373                 mem_ctx = talloc_new(req);
374                 if (mem_ctx == NULL) {
375                         return LDB_ERR_OPERATIONS_ERROR;
376                 }
377
378                 /* prepare the first operation */
379                 down_req = talloc(req, struct ldb_request);
380                 if (down_req == NULL) {
381                         ldb_set_errstring(module->ldb, "Out of memory!");
382                         talloc_free(mem_ctx);
383                         return LDB_ERR_OPERATIONS_ERROR;
384                 }
385                 
386                 *down_req = *req; /* copy the request */
387                 
388                 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
389                 
390                 if (down_req->op.add.message == NULL) {
391                         talloc_free(mem_ctx);
392                         return LDB_ERR_OPERATIONS_ERROR;
393                 }
394                 
395                 ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
396                 if (ret != LDB_SUCCESS) {
397                         return ret;
398                 }
399
400                 /* We must completely replace the existing objectClass entry,
401                  * because we need it sorted */
402                 
403                 ldb_msg_remove_attr(msg, "objectClass");
404                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
405                 
406                 if (ret != LDB_SUCCESS) {
407                         talloc_free(mem_ctx);
408                         return ret;
409                 }
410
411                 /* Move from the linked list back into an ldb msg */
412                 for (current = sorted; current; current = current->next) {
413                         ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
414                         if (ret != LDB_SUCCESS) {
415                                 ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
416                                 talloc_free(mem_ctx);
417                                 return ret;
418                         }
419                 }
420                 
421                 talloc_free(mem_ctx);
422
423                 ret = ldb_msg_sanity_check(module->ldb, msg);
424                 if (ret != LDB_SUCCESS) {
425                         talloc_free(mem_ctx);
426                         return ret;
427                 }
428                 
429                 /* go on with the call chain */
430                 ret = ldb_next_request(module, down_req);
431                 
432                 /* do not free down_req as the call results may be linked to it,
433                  * it will be freed when the upper level request get freed */
434                 if (ret == LDB_SUCCESS) {
435                         req->handle = down_req->handle;
436                 }
437                 return ret;
438         }
439         }
440
441         {
442                 struct ldb_handle *h;
443                 struct oc_context *ac;
444                 
445                 h = oc_init_handle(req, module);
446                 if (!h) {
447                         return LDB_ERR_OPERATIONS_ERROR;
448                 }
449                 ac = talloc_get_type(h->private_data, struct oc_context);
450                 
451                 /* return or own handle to deal with this call */
452                 req->handle = h;
453                 
454                 /* prepare the first operation */
455                 ac->down_req = talloc(ac, struct ldb_request);
456                 if (ac->down_req == NULL) {
457                         ldb_set_errstring(module->ldb, "Out of memory!");
458                         return LDB_ERR_OPERATIONS_ERROR;
459                 }
460                 
461                 *(ac->down_req) = *req; /* copy the request */
462                 
463                 ac->down_req->context = NULL;
464                 ac->down_req->callback = NULL;
465                 ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
466                 
467                 ac->step = OC_DO_REQ;
468
469                 return ldb_next_request(module, ac->down_req);
470         }
471 }
472
473 static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
474 {
475         struct oc_context *ac;
476
477         if (!context || !ares) {
478                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
479                 return LDB_ERR_OPERATIONS_ERROR;
480         }
481
482         ac = talloc_get_type(context, struct oc_context);
483
484         /* we are interested only in the single reply (base search) we receive here */
485         if (ares->type == LDB_REPLY_ENTRY) {
486                 if (ac->search_res != NULL) {
487                         ldb_set_errstring(ldb, "Too many results");
488                         talloc_free(ares);
489                         return LDB_ERR_OPERATIONS_ERROR;
490                 }
491
492                 ac->search_res = talloc_move(ac, &ares);
493         } else {
494                 talloc_free(ares);
495         }
496
497         return LDB_SUCCESS;
498 }
499
500 static int objectclass_search_self(struct ldb_handle *h) {
501
502         struct oc_context *ac;
503         static const char * const attrs[] = { "objectClass", NULL };
504
505         ac = talloc_get_type(h->private_data, struct oc_context);
506
507         /* prepare the search operation */
508         ac->search_req = talloc_zero(ac, struct ldb_request);
509         if (ac->search_req == NULL) {
510                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
511                 return LDB_ERR_OPERATIONS_ERROR;
512         }
513
514         ac->search_req->operation = LDB_SEARCH;
515         ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
516         ac->search_req->op.search.scope = LDB_SCOPE_BASE;
517         ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL);
518         if (ac->search_req->op.search.tree == NULL) {
519                 ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search");
520                 return LDB_ERR_OPERATIONS_ERROR;
521         }
522         ac->search_req->op.search.attrs = attrs;
523         ac->search_req->controls = NULL;
524         ac->search_req->context = ac;
525         ac->search_req->callback = get_self_callback;
526         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
527
528         ac->step = OC_SEARCH_SELF;
529
530         return ldb_next_request(ac->module, ac->search_req);
531 }
532
533 static int objectclass_do_mod(struct ldb_handle *h) {
534
535         struct oc_context *ac;
536         struct ldb_message_element *objectclass_element;
537         struct ldb_message *msg;
538         TALLOC_CTX *mem_ctx;
539         struct class_list *sorted, *current;
540         int ret;
541       
542         ac = talloc_get_type(h->private_data, struct oc_context);
543
544         mem_ctx = talloc_new(ac);
545         if (mem_ctx == NULL) {
546                 return LDB_ERR_OPERATIONS_ERROR;
547         }
548
549         ac->mod_req = talloc(ac, struct ldb_request);
550         if (ac->mod_req == NULL) {
551                 talloc_free(mem_ctx);
552                 return LDB_ERR_OPERATIONS_ERROR;
553         }
554
555         ac->mod_req->operation = LDB_MODIFY;
556         ac->mod_req->controls = NULL;
557         ac->mod_req->context = ac;
558         ac->mod_req->callback = NULL;
559         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
560         
561         /* use a new message structure */
562         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
563         if (msg == NULL) {
564                 ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
565                 talloc_free(mem_ctx);
566                 return LDB_ERR_OPERATIONS_ERROR;
567         }
568
569         /* This is now the objectClass list from the database */
570         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
571                                                    "objectClass");
572         if (!objectclass_element) {
573                 /* Where did it go?  Move along now, nothing to see here */
574                 talloc_free(mem_ctx);
575                 return LDB_SUCCESS;
576         }
577         
578         /* modify dn */
579         msg->dn = ac->orig_req->op.mod.message->dn;
580
581         ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted);
582         if (ret != LDB_SUCCESS) {
583                 return ret;
584         }
585
586         /* We must completely replace the existing objectClass entry.
587          * We could do a constrained add/del, but we are meant to be
588          * in a transaction... */
589
590         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
591         if (ret != LDB_SUCCESS) {
592                 ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
593                 talloc_free(mem_ctx);
594                 return ret;
595         }
596         
597         /* Move from the linked list back into an ldb msg */
598         for (current = sorted; current; current = current->next) {
599                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
600                 if (ret != LDB_SUCCESS) {
601                         ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
602                         talloc_free(mem_ctx);
603                         return ret;
604                 }
605         }
606
607         ret = ldb_msg_sanity_check(ac->module->ldb, msg);
608         if (ret != LDB_SUCCESS) {
609                 talloc_free(mem_ctx);
610                 return ret;
611         }
612
613
614         h->state = LDB_ASYNC_INIT;
615         h->status = LDB_SUCCESS;
616
617         ac->step = OC_DO_MOD;
618
619         talloc_free(mem_ctx);
620         /* perform the search */
621         return ldb_next_request(ac->module, ac->mod_req);
622 }
623
624 static int oc_wait(struct ldb_handle *handle) {
625         struct oc_context *ac;
626         int ret;
627     
628         if (!handle || !handle->private_data) {
629                 return LDB_ERR_OPERATIONS_ERROR;
630         }
631
632         if (handle->state == LDB_ASYNC_DONE) {
633                 return handle->status;
634         }
635
636         handle->state = LDB_ASYNC_PENDING;
637         handle->status = LDB_SUCCESS;
638
639         ac = talloc_get_type(handle->private_data, struct oc_context);
640
641         switch (ac->step) {
642         case OC_DO_REQ:
643                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
644
645                 if (ret != LDB_SUCCESS) {
646                         handle->status = ret;
647                         goto done;
648                 }
649                 if (ac->down_req->handle->status != LDB_SUCCESS) {
650                         handle->status = ac->down_req->handle->status;
651                         goto done;
652                 }
653
654                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
655                         return LDB_SUCCESS;
656                 }
657
658                 /* mods done, go on */
659                 return objectclass_search_self(handle);
660
661         case OC_SEARCH_SELF:
662                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
663
664                 if (ret != LDB_SUCCESS) {
665                         handle->status = ret;
666                         goto done;
667                 }
668                 if (ac->search_req->handle->status != LDB_SUCCESS) {
669                         handle->status = ac->search_req->handle->status;
670                         goto done;
671                 }
672
673                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
674                         return LDB_SUCCESS;
675                 }
676
677                 /* self search done, go on */
678                 return objectclass_do_mod(handle);
679
680         case OC_DO_MOD:
681                 ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
682
683                 if (ret != LDB_SUCCESS) {
684                         handle->status = ret;
685                         goto done;
686                 }
687                 if (ac->mod_req->handle->status != LDB_SUCCESS) {
688                         handle->status = ac->mod_req->handle->status;
689                         goto done;
690                 }
691
692                 if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
693                         return LDB_SUCCESS;
694                 }
695
696                 break;
697                 
698         default:
699                 ret = LDB_ERR_OPERATIONS_ERROR;
700                 goto done;
701         }
702
703         ret = LDB_SUCCESS;
704
705 done:
706         handle->state = LDB_ASYNC_DONE;
707         return ret;
708 }
709
710 static int oc_wait_all(struct ldb_handle *handle) {
711
712         int ret;
713
714         while (handle->state != LDB_ASYNC_DONE) {
715                 ret = oc_wait(handle);
716                 if (ret != LDB_SUCCESS) {
717                         return ret;
718                 }
719         }
720
721         return handle->status;
722 }
723
724 static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
725 {
726         if (type == LDB_WAIT_ALL) {
727                 return oc_wait_all(handle);
728         } else {
729                 return oc_wait(handle);
730         }
731 }
732
733 static const struct ldb_module_ops objectclass_ops = {
734         .name              = "objectclass",
735         .add           = objectclass_add,
736         .modify        = objectclass_modify,
737         .wait          = objectclass_wait
738 };
739
740 int ldb_objectclass_init(void)
741 {
742         return ldb_register_module(&objectclass_ops);
743 }
744