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