Don't segfault on invalid objectClass input.
[sfrench/samba-autobuild/.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: 
27  *  - sort the objectClass attribute into the class
28  *    hierarchy, 
29  *  - fix DNs and attributes into 'standard' case
30  *  - Add objectCategory and ntSecurityDescriptor defaults
31  *
32  *  Author: Andrew Bartlett
33  */
34
35
36 #include "includes.h"
37 #include "ldb/include/ldb.h"
38 #include "ldb/include/ldb_errors.h"
39 #include "ldb/include/ldb_private.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "lib/util/dlinklist.h"
42 #include "librpc/ndr/libndr.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "libcli/security/security.h"
45 #include "auth/auth.h"
46 #include "param/param.h"
47
48 struct oc_context {
49
50         enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD, 
51                       OC_SEARCH_ADD_PARENT, OC_DO_ADD, 
52                       OC_SEARCH_RENAME_PARENT, OC_DO_RENAME} step;
53
54         struct ldb_module *module;
55         struct ldb_request *orig_req;
56
57         struct ldb_request *down_req;
58
59         struct ldb_request *search_req;
60         struct ldb_reply *search_res;
61
62         struct ldb_request *add_req;
63         struct ldb_request *mod_req;
64         struct ldb_request *rename_req;
65 };
66
67 struct class_list {
68         struct class_list *prev, *next;
69         const struct dsdb_class *objectclass;
70 };
71
72 static int objectclass_do_add(struct ldb_handle *h);
73
74 static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
75 {
76         struct oc_context *ac;
77         struct ldb_handle *h;
78
79         h = talloc_zero(req, struct ldb_handle);
80         if (h == NULL) {
81                 ldb_set_errstring(module->ldb, "Out of Memory");
82                 return NULL;
83         }
84
85         h->module = module;
86
87         ac = talloc_zero(h, struct oc_context);
88         if (ac == NULL) {
89                 ldb_set_errstring(module->ldb, "Out of Memory");
90                 talloc_free(h);
91                 return NULL;
92         }
93
94         h->private_data = (void *)ac;
95
96         h->state = LDB_ASYNC_INIT;
97         h->status = LDB_SUCCESS;
98
99         ac->module = module;
100         ac->orig_req = req;
101
102         return h;
103 }
104
105 /* Sort objectClasses into correct order, and validate that all
106  * objectClasses specified actually exist in the schema
107  */
108
109 static int objectclass_sort(struct ldb_module *module,
110                             const struct dsdb_schema *schema,
111                             struct ldb_message *msg, /* so that when we create new elements, we put it on the right parent */
112                             TALLOC_CTX *mem_ctx,
113                             struct ldb_message_element *objectclass_element,
114                             struct class_list **sorted_out) 
115 {
116         int i;
117         int layer;
118         struct class_list *sorted = NULL, *parent_class = NULL,
119                 *subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent;
120         /* DESIGN:
121          *
122          * We work on 4 different 'bins' (implemented here as linked lists):
123          *
124          * * sorted:       the eventual list, in the order we wish to push
125          *                 into the database.  This is the only ordered list.
126          *
127          * * parent_class: The current parent class 'bin' we are
128          *                 trying to find subclasses for
129          *
130          * * subclass:     The subclasses we have found so far
131          *
132          * * unsorted:     The remaining objectClasses
133          *
134          * The process is a matter of filtering objectClasses up from
135          * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
136          * 
137          * We start with 'top' (found and promoted to parent_class
138          * initially).  Then we find (in unsorted) all the direct
139          * subclasses of 'top'.  parent_classes is concatenated onto
140          * the end of 'sorted', and subclass becomes the list in
141          * parent_class.
142          *
143          * We then repeat, until we find no more subclasses.  Any left
144          * over classes are added to the end.
145          *
146          */
147
148         /* Firstly, dump all the objectClass elements into the
149          * unsorted bin, except for 'top', which is special */
150         for (i=0; i < objectclass_element->num_values; i++) {
151                 current = talloc(mem_ctx, struct class_list);
152                 if (!current) {
153                         ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list");
154                         talloc_free(mem_ctx);
155                         return LDB_ERR_OPERATIONS_ERROR;
156                 }
157                 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, (const char *)objectclass_element->values[i].data);
158                 if (!current->objectclass) {
159                         ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in schema", (const char *)objectclass_element->values[i].data);
160                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
161                 }
162
163                 /* this is the root of the tree.  We will start
164                  * looking for subclasses from here */
165                 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) == 0) {
166                         DLIST_ADD_END(parent_class, current, struct class_list *);
167                 } else {
168                         DLIST_ADD_END(unsorted, current, struct class_list *);
169                 }
170         }
171
172         if (parent_class == NULL) {
173                 current = talloc(mem_ctx, struct class_list);
174                 current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
175                 DLIST_ADD_END(parent_class, current, struct class_list *);
176         }
177
178         /* For each object:  find parent chain */
179         for (current = unsorted; schema && current; current = current->next) {
180                 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
181                         if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
182                                 break;
183                         }
184                 }
185                 /* If we didn't get to the end of the list, we need to add this parent */
186                 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
187                         continue;
188                 }
189
190                 new_parent = talloc(mem_ctx, struct class_list);
191                 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
192                 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
193         }
194
195         /* DEBUGGING aid:  how many layers are we down now? */
196         layer = 0;
197         do {
198                 layer++;
199                 /* Find all the subclasses of classes in the
200                  * parent_classes.  Push them onto the subclass list */
201
202                 /* Ensure we don't bother if there are no unsorted entries left */
203                 for (current = parent_class; schema && unsorted && current; current = current->next) {
204                         /* Walk the list of possible subclasses in unsorted */
205                         for (poss_subclass = unsorted; poss_subclass; ) {
206                                 struct class_list *next;
207                                 
208                                 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
209                                 next = poss_subclass->next;
210
211                                 if (ldb_attr_cmp(poss_subclass->objectclass->subClassOf, current->objectclass->lDAPDisplayName) == 0) {
212                                         DLIST_REMOVE(unsorted, poss_subclass);
213                                         DLIST_ADD(subclass, poss_subclass);
214                                         
215                                         break;
216                                 }
217                                 poss_subclass = next;
218                         }
219                 }
220
221                 /* Now push the parent_classes as sorted, we are done with
222                 these.  Add to the END of the list by concatenation */
223                 DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
224
225                 /* and now find subclasses of these */
226                 parent_class = subclass;
227                 subclass = NULL;
228
229                 /* If we didn't find any subclasses we will fall out
230                  * the bottom here */
231         } while (parent_class);
232
233         if (!unsorted) {
234                 *sorted_out = sorted;
235                 return LDB_SUCCESS;
236         }
237
238         if (!schema) {
239                 /* If we don't have schema yet, then just merge the lists again */
240                 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
241                 *sorted_out = sorted;
242                 return LDB_SUCCESS;
243         }
244
245         /* This shouldn't happen, and would break MMC, perhaps there
246          * was no 'top', a conflict in the objectClasses or some other
247          * schema error?
248          */
249         ldb_asprintf_errstring(module->ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
250         return LDB_ERR_OBJECT_CLASS_VIOLATION;
251 }
252
253 static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, 
254                          const struct dsdb_class *objectclass) 
255 {
256         enum ndr_err_code ndr_err;
257         DATA_BLOB *linear_sd;
258         struct auth_session_info *session_info
259                 = ldb_get_opaque(module->ldb, "sessionInfo");
260         struct security_descriptor *sd;
261
262         if (!objectclass->defaultSecurityDescriptor) {
263                 return NULL;
264         }
265         
266         sd = sddl_decode(mem_ctx, 
267                          objectclass->defaultSecurityDescriptor,
268                          samdb_domain_sid(module->ldb));
269
270         if (!sd || !session_info || !session_info->security_token) {
271                 return NULL;
272         }
273         
274         sd->owner_sid = session_info->security_token->user_sid;
275         sd->group_sid = session_info->security_token->group_sid;
276         
277         linear_sd = talloc(mem_ctx, DATA_BLOB);
278         if (!linear_sd) {
279                 return NULL;
280         }
281
282         ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, 
283                                         lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
284                                        sd,
285                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
286         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
287                 return NULL;
288         }
289         
290         return linear_sd;
291
292 }
293
294 static int get_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
295 {
296         struct oc_context *ac;
297
298         ac = talloc_get_type(context, struct oc_context);
299
300         /* we are interested only in the single reply (base search) we receive here */
301         if (ares->type == LDB_REPLY_ENTRY) {
302                 if (ac->search_res != NULL) {
303                         ldb_set_errstring(ldb, "Too many results");
304                         talloc_free(ares);
305                         return LDB_ERR_OPERATIONS_ERROR;
306                 }
307
308                 ac->search_res = talloc_move(ac, &ares);
309         } else {
310                 talloc_free(ares);
311         }
312
313         return LDB_SUCCESS;
314 }
315
316 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
317
318    This should mean that if the parent is:
319     CN=Users,DC=samba,DC=example,DC=com
320    and a proposed child is
321     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
322
323    The resulting DN should be:
324
325     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
326    
327  */
328 static int fix_dn(TALLOC_CTX *mem_ctx, 
329                   struct ldb_dn *newdn, struct ldb_dn *parent_dn, 
330                   struct ldb_dn **fixed_dn) 
331 {
332         char *upper_rdn_attr;
333         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
334         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
335
336         /* We need the attribute name in upper case */
337         upper_rdn_attr = strupper_talloc(*fixed_dn, 
338                                          ldb_dn_get_rdn_name(newdn));
339         if (!upper_rdn_attr) {
340                 return LDB_ERR_OPERATIONS_ERROR;
341         }
342                                                
343         /* Create a new child */
344         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
345                 return LDB_ERR_OPERATIONS_ERROR;
346         }
347
348         /* And replace it with CN=foo (we need the attribute in upper case */
349         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr,
350                                     *ldb_dn_get_rdn_val(newdn));
351 }
352
353 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
354 static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg) 
355 {
356         int i;
357         for (i=0; i < msg->num_elements; i++) {
358                 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
359                 if (!attribute) {
360                         ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
361                         return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
362                 }
363                 msg->elements[i].name = attribute->lDAPDisplayName;
364         }
365
366         return LDB_SUCCESS;
367 }
368
369 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
370 {
371
372         static const char * const attrs[] = { NULL };
373
374         struct ldb_handle *h;
375         struct oc_context *ac;
376         struct ldb_dn *parent_dn;
377         int ret;
378         
379         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
380
381         /* do not manipulate our control entries */
382         if (ldb_dn_is_special(req->op.add.message->dn)) {
383                 return ldb_next_request(module, req);
384         }
385
386         /* Need to object to this, but cn=rootdse doesn't hae an objectClass... */
387         if (ldb_msg_find_element(req->op.add.message, 
388                                  "objectClass") == NULL) {
389                 return ldb_next_request(module, req);
390         }
391
392         h = oc_init_handle(req, module);
393         if (!h) {
394                 return LDB_ERR_OPERATIONS_ERROR;
395         }
396         ac = talloc_get_type(h->private_data, struct oc_context);
397         
398         /* return or own handle to deal with this call */
399         req->handle = h;
400
401         /* If there isn't a parent, just go on to the add processing */
402         if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) == 1) {
403                 return objectclass_do_add(h);
404         }
405
406         parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.add.message->dn);
407         if (parent_dn == NULL) {
408                 ldb_oom(module->ldb);
409                 return LDB_ERR_OPERATIONS_ERROR;
410         }
411
412         ret = ldb_build_search_req(&ac->search_req, module->ldb,
413                                    ac, parent_dn, LDB_SCOPE_BASE,
414                                    "(objectClass=*)",
415                                    attrs, NULL, 
416                                    ac, get_search_callback);
417         if (ret != LDB_SUCCESS) {
418                 return ret;
419         }
420
421         talloc_steal(ac->search_req, parent_dn);
422
423         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
424
425         ac->step = OC_SEARCH_ADD_PARENT;
426
427         return ldb_next_request(ac->module, ac->search_req);
428 }
429
430 static int objectclass_do_add(struct ldb_handle *h) 
431 {
432         const struct dsdb_schema *schema;
433         struct oc_context *ac;
434         struct ldb_message_element *objectclass_element;
435         struct ldb_message *msg;
436         TALLOC_CTX *mem_ctx;
437         struct class_list *sorted, *current;
438         int ret;
439       
440         ac = talloc_get_type(h->private_data, struct oc_context);
441         schema = dsdb_get_schema(ac->module->ldb);
442
443         mem_ctx = talloc_new(ac);
444         if (mem_ctx == NULL) {
445                 return LDB_ERR_OPERATIONS_ERROR;
446         }
447
448         ac->add_req = talloc(ac, struct ldb_request);
449         if (ac->add_req == NULL) {
450                 talloc_free(mem_ctx);
451                 return LDB_ERR_OPERATIONS_ERROR;
452         }
453
454         *ac->add_req = *ac->orig_req;
455
456         ac->add_req->op.add.message = msg = ldb_msg_copy_shallow(ac->add_req, ac->orig_req->op.add.message);
457
458         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->add_req);
459         
460         /* Check we have a valid parent */
461         if (ac->search_res == NULL) {
462                 if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) {
463                         /* Allow the tree to be started */
464                         
465                         /* but don't keep any error string, it's meaningless */
466                         ldb_set_errstring(ac->module->ldb, NULL);
467                 } else {
468                         ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!", 
469                                                ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
470                         return LDB_ERR_UNWILLING_TO_PERFORM;
471                 }
472         } else {
473                 
474                 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
475                 ret = fix_dn(msg, 
476                              ac->orig_req->op.add.message->dn,
477                              ac->search_res->message->dn,
478                              &msg->dn);
479
480                 if (ret != LDB_SUCCESS) {
481                         ldb_asprintf_errstring(ac->module->ldb, "Could not munge DN %s into normal form", 
482                                                ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
483                         return ret;
484                 }
485
486                 /* TODO: Check this is a valid child to this parent,
487                  * by reading the allowedChildClasses and
488                  * allowedChildClasssesEffective attributes */
489
490         }
491
492         if (schema) {
493                 ret = fix_attributes(ac->module->ldb, schema, msg);
494                 if (ret != LDB_SUCCESS) {
495                         talloc_free(mem_ctx);
496                         return ret;
497                 }
498
499                 /* This is now the objectClass list from the database */
500                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
501                 
502                 if (!objectclass_element) {
503                         /* Where did it go?  bail now... */
504                         talloc_free(mem_ctx);
505                         return LDB_ERR_OPERATIONS_ERROR;
506                 }
507                 ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
508                 if (ret != LDB_SUCCESS) {
509                         talloc_free(mem_ctx);
510                         return ret;
511                 }
512                 
513                 ldb_msg_remove_attr(msg, "objectClass");
514                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
515                 
516                 if (ret != LDB_SUCCESS) {
517                         talloc_free(mem_ctx);
518                         return ret;
519                 }
520                 
521                 /* We must completely replace the existing objectClass entry,
522                  * because we need it sorted */
523                 
524                 /* Move from the linked list back into an ldb msg */
525                 for (current = sorted; current; current = current->next) {
526                         ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
527                         if (ret != LDB_SUCCESS) {
528                                 ldb_set_errstring(ac->module->ldb, 
529                                                   "objectclass: could not re-add sorted "
530                                                   "objectclass to modify msg");
531                                 talloc_free(mem_ctx);
532                                 return ret;
533                         }
534                         /* Last one is the critical one */
535                         if (!current->next) {
536                                 if (!ldb_msg_find_element(msg, "objectCategory")) {
537                                         ldb_msg_add_string(msg, "objectCategory", 
538                                                            current->objectclass->defaultObjectCategory);
539                                 }
540                                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
541                                         ldb_msg_add_string(msg, "showInAdvancedViewOnly", 
542                                                            "TRUE");
543                                 }
544                                 if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) {
545                                         DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass);
546                                         if (sd) {
547                                                 ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd);
548                                         }
549                                 }
550                         }
551                 }
552         }
553
554         talloc_free(mem_ctx);
555         ret = ldb_msg_sanity_check(ac->module->ldb, msg);
556
557
558         if (ret != LDB_SUCCESS) {
559                 return ret;
560         }
561
562         h->state = LDB_ASYNC_INIT;
563         h->status = LDB_SUCCESS;
564
565         ac->step = OC_DO_ADD;
566
567         /* perform the add */
568         return ldb_next_request(ac->module, ac->add_req);
569 }
570
571 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
572 {
573         struct ldb_message_element *objectclass_element;
574         struct ldb_message *msg;
575         const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
576         int ret;
577
578         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
579
580         /* do not manipulate our control entries */
581         if (ldb_dn_is_special(req->op.mod.message->dn)) {
582                 return ldb_next_request(module, req);
583         }
584         
585         /* Without schema, there isn't much to do here */
586         if (!schema) {
587                 return ldb_next_request(module, req);
588         }
589         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
590
591         /* If no part of this touches the objectClass, then we don't
592          * need to make any changes.  */
593
594         /* If the only operation is the deletion of the objectClass
595          * then go on with just fixing the attribute case */
596         if (!objectclass_element) {
597                 struct ldb_request *down_req = talloc(req, struct ldb_request);
598                 if (down_req == NULL) {
599                         ldb_set_errstring(module->ldb, "Out of memory!");
600                         return LDB_ERR_OPERATIONS_ERROR;
601                 }
602                 
603                 *down_req = *req; /* copy the request */
604                 
605                 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
606                 
607                 if (down_req->op.mod.message == NULL) {
608                         return LDB_ERR_OPERATIONS_ERROR;
609                 }
610                 
611                 ret = fix_attributes(module->ldb, schema, msg);
612                 if (ret != LDB_SUCCESS) {
613                         return ret;
614                 }
615
616                 /* go on with the call chain */
617                 ret = ldb_next_request(module, down_req);
618                 
619                 /* do not free down_req as the call results may be linked to it,
620                  * it will be freed when the upper level request get freed */
621                 if (ret == LDB_SUCCESS) {
622                         req->handle = down_req->handle;
623                 }
624                 return ret;
625         }
626
627         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
628         case LDB_FLAG_MOD_DELETE:
629                 if (objectclass_element->num_values == 0) {
630                         return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
631                 }
632                 break;
633         case LDB_FLAG_MOD_REPLACE:
634         {
635                 struct ldb_request *down_req;
636                 struct class_list *sorted, *current;
637                 TALLOC_CTX *mem_ctx;
638                 mem_ctx = talloc_new(req);
639                 if (mem_ctx == NULL) {
640                         return LDB_ERR_OPERATIONS_ERROR;
641                 }
642
643                 /* prepare the first operation */
644                 down_req = talloc(req, struct ldb_request);
645                 if (down_req == NULL) {
646                         ldb_set_errstring(module->ldb, "Out of memory!");
647                         talloc_free(mem_ctx);
648                         return LDB_ERR_OPERATIONS_ERROR;
649                 }
650                 
651                 *down_req = *req; /* copy the request */
652                 
653                 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
654                 
655                 if (down_req->op.mod.message == NULL) {
656                         talloc_free(mem_ctx);
657                         return LDB_ERR_OPERATIONS_ERROR;
658                 }
659                 
660                 ret = fix_attributes(module->ldb, schema, msg);
661                 if (ret != LDB_SUCCESS) {
662                         talloc_free(mem_ctx);
663                         return ret;
664                 }
665
666                 ret = objectclass_sort(module, schema, msg, mem_ctx, objectclass_element, &sorted);
667                 if (ret != LDB_SUCCESS) {
668                         return ret;
669                 }
670
671                 /* We must completely replace the existing objectClass entry,
672                  * because we need it sorted */
673                 
674                 ldb_msg_remove_attr(msg, "objectClass");
675                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
676                 
677                 if (ret != LDB_SUCCESS) {
678                         talloc_free(mem_ctx);
679                         return ret;
680                 }
681
682                 /* Move from the linked list back into an ldb msg */
683                 for (current = sorted; current; current = current->next) {
684                         ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
685                         if (ret != LDB_SUCCESS) {
686                                 ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
687                                 talloc_free(mem_ctx);
688                                 return ret;
689                         }
690                 }
691                 
692                 talloc_free(mem_ctx);
693
694                 ret = ldb_msg_sanity_check(module->ldb, msg);
695                 if (ret != LDB_SUCCESS) {
696                         talloc_free(mem_ctx);
697                         return ret;
698                 }
699                 
700                 /* go on with the call chain */
701                 ret = ldb_next_request(module, down_req);
702                 
703                 /* do not free down_req as the call results may be linked to it,
704                  * it will be freed when the upper level request get freed */
705                 if (ret == LDB_SUCCESS) {
706                         req->handle = down_req->handle;
707                 }
708                 return ret;
709         }
710         }
711
712         /* This isn't the default branch of the switch, but a 'in any
713          * other case'.  When a delete isn't for all objectClasses for
714          * example
715          */
716         {
717                 struct ldb_handle *h;
718                 struct oc_context *ac;
719                 
720                 h = oc_init_handle(req, module);
721                 if (!h) {
722                         return LDB_ERR_OPERATIONS_ERROR;
723                 }
724                 ac = talloc_get_type(h->private_data, struct oc_context);
725                 
726                 /* return or own handle to deal with this call */
727                 req->handle = h;
728                 
729                 /* prepare the first operation */
730                 ac->down_req = talloc(ac, struct ldb_request);
731                 if (ac->down_req == NULL) {
732                         ldb_oom(ac->module->ldb);
733                         return LDB_ERR_OPERATIONS_ERROR;
734                 }
735                 
736                 *(ac->down_req) = *req; /* copy the request */
737                 
738                 ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
739                 
740                 if (ac->down_req->op.mod.message == NULL) {
741                         ldb_oom(ac->module->ldb);
742                         return LDB_ERR_OPERATIONS_ERROR;
743                 }
744                 
745                 ret = fix_attributes(ac->module->ldb, schema, msg);
746                 if (ret != LDB_SUCCESS) {
747                         ldb_oom(ac->module->ldb);
748                         return ret;
749                 }
750
751                 ac->down_req->context = NULL;
752                 ac->down_req->callback = NULL;
753                 ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
754                 
755                 ac->step = OC_DO_REQ;
756
757                 return ldb_next_request(module, ac->down_req);
758         }
759 }
760
761 static int objectclass_search_self(struct ldb_handle *h) 
762 {
763         int ret;
764         struct oc_context *ac;
765         static const char * const attrs[] = { "objectClass", NULL };
766
767         ac = talloc_get_type(h->private_data, struct oc_context);
768
769         ret = ldb_build_search_req(&ac->search_req, ac->module->ldb,
770                                    ac, ac->orig_req->op.mod.message->dn, LDB_SCOPE_BASE,
771                                    "(objectClass=*)",
772                                    attrs, NULL, 
773                                    ac, get_search_callback);
774
775         if (ret != LDB_SUCCESS) {
776                 return ret;
777         }
778
779         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
780
781         ac->step = OC_SEARCH_SELF;
782
783         return ldb_next_request(ac->module, ac->search_req);
784 }
785
786 static int objectclass_do_mod(struct ldb_handle *h) {
787
788         const struct dsdb_schema *schema;
789         struct oc_context *ac;
790         struct ldb_message_element *objectclass_element;
791         struct ldb_message *msg;
792         TALLOC_CTX *mem_ctx;
793         struct class_list *sorted, *current;
794         int ret;
795       
796         ac = talloc_get_type(h->private_data, struct oc_context);
797         schema = dsdb_get_schema(ac->module->ldb);
798
799         mem_ctx = talloc_new(ac);
800         if (mem_ctx == NULL) {
801                 return LDB_ERR_OPERATIONS_ERROR;
802         }
803
804         ac->mod_req = talloc(ac, struct ldb_request);
805         if (ac->mod_req == NULL) {
806                 talloc_free(mem_ctx);
807                 return LDB_ERR_OPERATIONS_ERROR;
808         }
809
810         ac->mod_req->operation = LDB_MODIFY;
811         ac->mod_req->controls = NULL;
812         ac->mod_req->context = ac;
813         ac->mod_req->callback = NULL;
814         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
815         
816         /* use a new message structure */
817         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
818         if (msg == NULL) {
819                 ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
820                 talloc_free(mem_ctx);
821                 return LDB_ERR_OPERATIONS_ERROR;
822         }
823
824         /* This is now the objectClass list from the database */
825         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
826                                                    "objectClass");
827         if (!objectclass_element) {
828                 /* Where did it go?  bail now... */
829                 talloc_free(mem_ctx);
830                 return LDB_ERR_OPERATIONS_ERROR;
831         }
832         
833         /* modify dn */
834         msg->dn = ac->orig_req->op.mod.message->dn;
835
836         ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
837         if (ret != LDB_SUCCESS) {
838                 return ret;
839         }
840
841         /* We must completely replace the existing objectClass entry.
842          * We could do a constrained add/del, but we are meant to be
843          * in a transaction... */
844
845         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
846         if (ret != LDB_SUCCESS) {
847                 ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
848                 talloc_free(mem_ctx);
849                 return ret;
850         }
851         
852         /* Move from the linked list back into an ldb msg */
853         for (current = sorted; current; current = current->next) {
854                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
855                 if (ret != LDB_SUCCESS) {
856                         ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
857                         talloc_free(mem_ctx);
858                         return ret;
859                 }
860         }
861
862         ret = ldb_msg_sanity_check(ac->module->ldb, msg);
863         if (ret != LDB_SUCCESS) {
864                 talloc_free(mem_ctx);
865                 return ret;
866         }
867
868
869         h->state = LDB_ASYNC_INIT;
870         h->status = LDB_SUCCESS;
871
872         ac->step = OC_DO_MOD;
873
874         talloc_free(mem_ctx);
875         /* perform the search */
876         return ldb_next_request(ac->module, ac->mod_req);
877 }
878
879 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
880 {
881
882         static const char * const attrs[] = { NULL };
883
884         struct ldb_handle *h;
885         struct oc_context *ac;
886         struct ldb_dn *parent_dn;
887         int ret;
888         
889         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
890
891         if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
892                 return ldb_next_request(module, req);
893         }
894         
895         /* Firstly ensure we are not trying to rename it to be a child of itself */
896         if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
897             && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
898                 ldb_asprintf_errstring(module->ldb, "Cannot rename %s to be a child of itself",
899                                        ldb_dn_get_linearized(req->op.rename.olddn));
900                 return LDB_ERR_UNWILLING_TO_PERFORM;
901         }
902
903         h = oc_init_handle(req, module);
904         if (!h) {
905                 return LDB_ERR_OPERATIONS_ERROR;
906         }
907         ac = talloc_get_type(h->private_data, struct oc_context);
908         
909         /* return or own handle to deal with this call */
910         req->handle = h;
911
912         parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.rename.newdn);
913         if (parent_dn == NULL) {
914                 ldb_oom(module->ldb);
915                 return LDB_ERR_OPERATIONS_ERROR;
916         }
917         ret = ldb_build_search_req(&ac->search_req, module->ldb,
918                                    ac, parent_dn, LDB_SCOPE_BASE,
919                                    "(objectClass=*)",
920                                    attrs, NULL, 
921                                    ac, get_search_callback);
922         if (ret != LDB_SUCCESS) {
923                 return ret;
924         }
925         talloc_steal(ac->search_req, parent_dn);
926         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
927
928         ac->step = OC_SEARCH_RENAME_PARENT;
929
930         return ldb_next_request(ac->module, ac->search_req);
931 }
932
933 static int objectclass_do_rename(struct ldb_handle *h) 
934 {
935         struct oc_context *ac;
936         int ret;
937       
938         ac = talloc_get_type(h->private_data, struct oc_context);
939
940         ac->rename_req = talloc(ac, struct ldb_request);
941         if (ac->rename_req == NULL) {
942                 return LDB_ERR_OPERATIONS_ERROR;
943         }
944
945         *ac->rename_req = *ac->orig_req;
946
947         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->rename_req);
948         
949         /* Check we have a valid parent */
950         if (ac->search_res == NULL) {
951                 ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot rename %s, parent does not exist!", 
952                                        ldb_dn_get_linearized(ac->orig_req->op.rename.newdn));
953                 return LDB_ERR_UNWILLING_TO_PERFORM;
954         }
955         
956         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
957         ret = fix_dn(ac->rename_req, 
958                      ac->orig_req->op.rename.newdn, 
959                      ac->search_res->message->dn, 
960                      &ac->rename_req->op.rename.newdn);
961
962         if (ret != LDB_SUCCESS) {
963                 return ret;
964         }
965
966         /* TODO: Check this is a valid child to this parent,
967          * by reading the allowedChildClasses and
968          * allowedChildClasssesEffective attributes */
969
970         h->state = LDB_ASYNC_INIT;
971         h->status = LDB_SUCCESS;
972
973         ac->step = OC_DO_RENAME;
974
975         /* perform the rename */
976         return ldb_next_request(ac->module, ac->rename_req);
977 }
978
979 static int oc_wait(struct ldb_handle *handle) {
980         struct oc_context *ac;
981         int ret;
982     
983         if (!handle || !handle->private_data) {
984                 return LDB_ERR_OPERATIONS_ERROR;
985         }
986
987         if (handle->state == LDB_ASYNC_DONE) {
988                 return handle->status;
989         }
990
991         handle->state = LDB_ASYNC_PENDING;
992         handle->status = LDB_SUCCESS;
993
994         ac = talloc_get_type(handle->private_data, struct oc_context);
995
996         switch (ac->step) {
997         case OC_DO_REQ:
998                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
999
1000                 if (ret != LDB_SUCCESS) {
1001                         handle->status = ret;
1002                         goto done;
1003                 }
1004                 if (ac->down_req->handle->status != LDB_SUCCESS) {
1005                         handle->status = ac->down_req->handle->status;
1006                         goto done;
1007                 }
1008
1009                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
1010                         return LDB_SUCCESS;
1011                 }
1012
1013                 /* mods done, go on */
1014                 return objectclass_search_self(handle);
1015
1016         case OC_SEARCH_SELF:
1017                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
1018
1019                 if (ret != LDB_SUCCESS) {
1020                         handle->status = ret;
1021                         goto done;
1022                 }
1023                 if (ac->search_req->handle->status != LDB_SUCCESS) {
1024                         handle->status = ac->search_req->handle->status;
1025                         goto done;
1026                 }
1027
1028                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
1029                         return LDB_SUCCESS;
1030                 }
1031
1032                 /* self search done, go on */
1033                 return objectclass_do_mod(handle);
1034
1035         case OC_DO_MOD:
1036                 ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
1037
1038                 if (ret != LDB_SUCCESS) {
1039                         handle->status = ret;
1040                         goto done;
1041                 }
1042                 if (ac->mod_req->handle->status != LDB_SUCCESS) {
1043                         handle->status = ac->mod_req->handle->status;
1044                         goto done;
1045                 }
1046
1047                 if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
1048                         return LDB_SUCCESS;
1049                 }
1050
1051                 break;
1052                 
1053         case OC_SEARCH_ADD_PARENT:
1054                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
1055
1056                 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
1057                         handle->status = ret;
1058                         goto done;
1059                 }
1060                 if (ac->search_req->handle->status != LDB_SUCCESS
1061                     && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
1062                         handle->status = ac->search_req->handle->status;
1063                         goto done;
1064                 }
1065
1066                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
1067                         return LDB_SUCCESS;
1068                 }
1069
1070                 /* parent search done, go on */
1071                 return objectclass_do_add(handle);
1072
1073         case OC_DO_ADD:
1074                 ret = ldb_wait(ac->add_req->handle, LDB_WAIT_NONE);
1075
1076                 if (ret != LDB_SUCCESS) {
1077                         handle->status = ret;
1078                         goto done;
1079                 }
1080                 if (ac->add_req->handle->status != LDB_SUCCESS) {
1081                         handle->status = ac->add_req->handle->status;
1082                         goto done;
1083                 }
1084
1085                 if (ac->add_req->handle->state != LDB_ASYNC_DONE) {
1086                         return LDB_SUCCESS;
1087                 }
1088
1089                 break;
1090                 
1091         case OC_SEARCH_RENAME_PARENT:
1092                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
1093
1094                 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
1095                         handle->status = ret;
1096                         goto done;
1097                 }
1098                 if (ac->search_req->handle->status != LDB_SUCCESS && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
1099                         handle->status = ac->search_req->handle->status;
1100                         goto done;
1101                 }
1102
1103                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
1104                         return LDB_SUCCESS;
1105                 }
1106
1107                 /* parent search done, go on */
1108                 return objectclass_do_rename(handle);
1109
1110         case OC_DO_RENAME:
1111                 ret = ldb_wait(ac->rename_req->handle, LDB_WAIT_NONE);
1112
1113                 if (ret != LDB_SUCCESS) {
1114                         handle->status = ret;
1115                         goto done;
1116                 }
1117                 if (ac->rename_req->handle->status != LDB_SUCCESS) {
1118                         handle->status = ac->rename_req->handle->status;
1119                         goto done;
1120                 }
1121
1122                 if (ac->rename_req->handle->state != LDB_ASYNC_DONE) {
1123                         return LDB_SUCCESS;
1124                 }
1125
1126                 break;
1127                 
1128         default:
1129                 ret = LDB_ERR_OPERATIONS_ERROR;
1130                 goto done;
1131         }
1132
1133         ret = LDB_SUCCESS;
1134
1135 done:
1136         handle->state = LDB_ASYNC_DONE;
1137         return ret;
1138 }
1139
1140 static int oc_wait_all(struct ldb_handle *handle) {
1141
1142         int ret;
1143
1144         while (handle->state != LDB_ASYNC_DONE) {
1145                 ret = oc_wait(handle);
1146                 if (ret != LDB_SUCCESS) {
1147                         return ret;
1148                 }
1149         }
1150
1151         return handle->status;
1152 }
1153
1154 static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1155 {
1156         if (type == LDB_WAIT_ALL) {
1157                 return oc_wait_all(handle);
1158         } else {
1159                 return oc_wait(handle);
1160         }
1161 }
1162
1163 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1164         .name              = "objectclass",
1165         .add           = objectclass_add,
1166         .modify        = objectclass_modify,
1167         .rename        = objectclass_rename,
1168         .wait          = objectclass_wait
1169 };