4d4ef585cbb43bf6947ae49774420b90d003ee66
[metze/samba/wb-ndr.git] / source / 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         struct dom_sid *domain_sid = samdb_domain_sid(module->ldb);
262
263         if (!objectclass->defaultSecurityDescriptor || !domain_sid) {
264                 return NULL;
265         }
266         
267         sd = sddl_decode(mem_ctx, 
268                          objectclass->defaultSecurityDescriptor,
269                          domain_sid);
270
271         if (!sd || !session_info || !session_info->security_token) {
272                 return NULL;
273         }
274         
275         sd->owner_sid = session_info->security_token->user_sid;
276         sd->group_sid = session_info->security_token->group_sid;
277         
278         linear_sd = talloc(mem_ctx, DATA_BLOB);
279         if (!linear_sd) {
280                 return NULL;
281         }
282
283         ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, 
284                                         lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
285                                        sd,
286                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
287         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
288                 return NULL;
289         }
290         
291         return linear_sd;
292
293 }
294
295 static int get_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
296 {
297         struct oc_context *ac;
298
299         ac = talloc_get_type(context, struct oc_context);
300
301         /* we are interested only in the single reply (base search) we receive here */
302         if (ares->type == LDB_REPLY_ENTRY) {
303                 if (ac->search_res != NULL) {
304                         ldb_set_errstring(ldb, "Too many results");
305                         talloc_free(ares);
306                         return LDB_ERR_OPERATIONS_ERROR;
307                 }
308
309                 ac->search_res = talloc_move(ac, &ares);
310         } else {
311                 talloc_free(ares);
312         }
313
314         return LDB_SUCCESS;
315 }
316
317 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
318
319    This should mean that if the parent is:
320     CN=Users,DC=samba,DC=example,DC=com
321    and a proposed child is
322     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
323
324    The resulting DN should be:
325
326     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
327    
328  */
329 static int fix_dn(TALLOC_CTX *mem_ctx, 
330                   struct ldb_dn *newdn, struct ldb_dn *parent_dn, 
331                   struct ldb_dn **fixed_dn) 
332 {
333         char *upper_rdn_attr;
334         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
335         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
336
337         /* We need the attribute name in upper case */
338         upper_rdn_attr = strupper_talloc(*fixed_dn, 
339                                          ldb_dn_get_rdn_name(newdn));
340         if (!upper_rdn_attr) {
341                 return LDB_ERR_OPERATIONS_ERROR;
342         }
343                                                
344         /* Create a new child */
345         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
346                 return LDB_ERR_OPERATIONS_ERROR;
347         }
348
349         /* And replace it with CN=foo (we need the attribute in upper case */
350         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr,
351                                     *ldb_dn_get_rdn_val(newdn));
352 }
353
354 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
355 static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *schema, struct ldb_message *msg) 
356 {
357         int i;
358         for (i=0; i < msg->num_elements; i++) {
359                 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
360                 if (!attribute) {
361                         ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
362                         return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
363                 }
364                 msg->elements[i].name = attribute->lDAPDisplayName;
365         }
366
367         return LDB_SUCCESS;
368 }
369
370 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
371 {
372
373         static const char * const attrs[] = { NULL };
374
375         struct ldb_handle *h;
376         struct oc_context *ac;
377         struct ldb_dn *parent_dn;
378         int ret;
379         
380         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
381
382         /* do not manipulate our control entries */
383         if (ldb_dn_is_special(req->op.add.message->dn)) {
384                 return ldb_next_request(module, req);
385         }
386
387         /* Need to object to this, but cn=rootdse doesn't hae an objectClass... */
388         if (ldb_msg_find_element(req->op.add.message, 
389                                  "objectClass") == NULL) {
390                 return ldb_next_request(module, req);
391         }
392
393         h = oc_init_handle(req, module);
394         if (!h) {
395                 return LDB_ERR_OPERATIONS_ERROR;
396         }
397         ac = talloc_get_type(h->private_data, struct oc_context);
398         
399         /* return or own handle to deal with this call */
400         req->handle = h;
401
402         /* If there isn't a parent, just go on to the add processing */
403         if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) == 1) {
404                 return objectclass_do_add(h);
405         }
406
407         parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.add.message->dn);
408         if (parent_dn == NULL) {
409                 ldb_oom(module->ldb);
410                 return LDB_ERR_OPERATIONS_ERROR;
411         }
412
413         ret = ldb_build_search_req(&ac->search_req, module->ldb,
414                                    ac, parent_dn, LDB_SCOPE_BASE,
415                                    "(objectClass=*)",
416                                    attrs, NULL, 
417                                    ac, get_search_callback);
418         if (ret != LDB_SUCCESS) {
419                 return ret;
420         }
421
422         talloc_steal(ac->search_req, parent_dn);
423
424         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
425
426         ac->step = OC_SEARCH_ADD_PARENT;
427
428         return ldb_next_request(ac->module, ac->search_req);
429 }
430
431 static int objectclass_do_add(struct ldb_handle *h) 
432 {
433         const struct dsdb_schema *schema;
434         struct oc_context *ac;
435         struct ldb_message_element *objectclass_element;
436         struct ldb_message *msg;
437         TALLOC_CTX *mem_ctx;
438         struct class_list *sorted, *current;
439         int ret;
440       
441         ac = talloc_get_type(h->private_data, struct oc_context);
442         schema = dsdb_get_schema(ac->module->ldb);
443
444         mem_ctx = talloc_new(ac);
445         if (mem_ctx == NULL) {
446                 return LDB_ERR_OPERATIONS_ERROR;
447         }
448
449         ac->add_req = talloc(ac, struct ldb_request);
450         if (ac->add_req == NULL) {
451                 talloc_free(mem_ctx);
452                 return LDB_ERR_OPERATIONS_ERROR;
453         }
454
455         *ac->add_req = *ac->orig_req;
456
457         ac->add_req->op.add.message = msg = ldb_msg_copy_shallow(ac->add_req, ac->orig_req->op.add.message);
458
459         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->add_req);
460         
461         /* Check we have a valid parent */
462         if (ac->search_res == NULL) {
463                 if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) {
464                         /* Allow the tree to be started */
465                         
466                         /* but don't keep any error string, it's meaningless */
467                         ldb_set_errstring(ac->module->ldb, NULL);
468                 } else {
469                         ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!", 
470                                                ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
471                         return LDB_ERR_UNWILLING_TO_PERFORM;
472                 }
473         } else {
474                 
475                 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
476                 ret = fix_dn(msg, 
477                              ac->orig_req->op.add.message->dn,
478                              ac->search_res->message->dn,
479                              &msg->dn);
480
481                 if (ret != LDB_SUCCESS) {
482                         ldb_asprintf_errstring(ac->module->ldb, "Could not munge DN %s into normal form", 
483                                                ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
484                         return ret;
485                 }
486
487                 /* TODO: Check this is a valid child to this parent,
488                  * by reading the allowedChildClasses and
489                  * allowedChildClasssesEffective attributes */
490
491         }
492
493         if (schema) {
494                 ret = fix_attributes(ac->module->ldb, schema, msg);
495                 if (ret != LDB_SUCCESS) {
496                         talloc_free(mem_ctx);
497                         return ret;
498                 }
499
500                 /* This is now the objectClass list from the database */
501                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
502                 
503                 if (!objectclass_element) {
504                         /* Where did it go?  bail now... */
505                         talloc_free(mem_ctx);
506                         return LDB_ERR_OPERATIONS_ERROR;
507                 }
508                 ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
509                 if (ret != LDB_SUCCESS) {
510                         talloc_free(mem_ctx);
511                         return ret;
512                 }
513                 
514                 ldb_msg_remove_attr(msg, "objectClass");
515                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
516                 
517                 if (ret != LDB_SUCCESS) {
518                         talloc_free(mem_ctx);
519                         return ret;
520                 }
521                 
522                 /* We must completely replace the existing objectClass entry,
523                  * because we need it sorted */
524                 
525                 /* Move from the linked list back into an ldb msg */
526                 for (current = sorted; current; current = current->next) {
527                         ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
528                         if (ret != LDB_SUCCESS) {
529                                 ldb_set_errstring(ac->module->ldb, 
530                                                   "objectclass: could not re-add sorted "
531                                                   "objectclass to modify msg");
532                                 talloc_free(mem_ctx);
533                                 return ret;
534                         }
535                         /* Last one is the critical one */
536                         if (!current->next) {
537                                 if (!ldb_msg_find_element(msg, "objectCategory")) {
538                                         ldb_msg_add_string(msg, "objectCategory", 
539                                                            current->objectclass->defaultObjectCategory);
540                                 }
541                                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
542                                         ldb_msg_add_string(msg, "showInAdvancedViewOnly", 
543                                                            "TRUE");
544                                 }
545                                 if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) {
546                                         DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass);
547                                         if (sd) {
548                                                 ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd);
549                                         }
550                                 }
551                         }
552                 }
553         }
554
555         talloc_free(mem_ctx);
556         ret = ldb_msg_sanity_check(ac->module->ldb, msg);
557
558
559         if (ret != LDB_SUCCESS) {
560                 return ret;
561         }
562
563         h->state = LDB_ASYNC_INIT;
564         h->status = LDB_SUCCESS;
565
566         ac->step = OC_DO_ADD;
567
568         /* perform the add */
569         return ldb_next_request(ac->module, ac->add_req);
570 }
571
572 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
573 {
574         struct ldb_message_element *objectclass_element;
575         struct ldb_message *msg;
576         const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
577         int ret;
578
579         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
580
581         /* do not manipulate our control entries */
582         if (ldb_dn_is_special(req->op.mod.message->dn)) {
583                 return ldb_next_request(module, req);
584         }
585         
586         /* Without schema, there isn't much to do here */
587         if (!schema) {
588                 return ldb_next_request(module, req);
589         }
590         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
591
592         /* If no part of this touches the objectClass, then we don't
593          * need to make any changes.  */
594
595         /* If the only operation is the deletion of the objectClass
596          * then go on with just fixing the attribute case */
597         if (!objectclass_element) {
598                 struct ldb_request *down_req = talloc(req, struct ldb_request);
599                 if (down_req == NULL) {
600                         ldb_set_errstring(module->ldb, "Out of memory!");
601                         return LDB_ERR_OPERATIONS_ERROR;
602                 }
603                 
604                 *down_req = *req; /* copy the request */
605                 
606                 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
607                 
608                 if (down_req->op.mod.message == NULL) {
609                         return LDB_ERR_OPERATIONS_ERROR;
610                 }
611                 
612                 ret = fix_attributes(module->ldb, schema, msg);
613                 if (ret != LDB_SUCCESS) {
614                         return ret;
615                 }
616
617                 /* go on with the call chain */
618                 ret = ldb_next_request(module, down_req);
619                 
620                 /* do not free down_req as the call results may be linked to it,
621                  * it will be freed when the upper level request get freed */
622                 if (ret == LDB_SUCCESS) {
623                         req->handle = down_req->handle;
624                 }
625                 return ret;
626         }
627
628         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
629         case LDB_FLAG_MOD_DELETE:
630                 if (objectclass_element->num_values == 0) {
631                         return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
632                 }
633                 break;
634         case LDB_FLAG_MOD_REPLACE:
635         {
636                 struct ldb_request *down_req;
637                 struct class_list *sorted, *current;
638                 TALLOC_CTX *mem_ctx;
639                 mem_ctx = talloc_new(req);
640                 if (mem_ctx == NULL) {
641                         return LDB_ERR_OPERATIONS_ERROR;
642                 }
643
644                 /* prepare the first operation */
645                 down_req = talloc(req, struct ldb_request);
646                 if (down_req == NULL) {
647                         ldb_set_errstring(module->ldb, "Out of memory!");
648                         talloc_free(mem_ctx);
649                         return LDB_ERR_OPERATIONS_ERROR;
650                 }
651                 
652                 *down_req = *req; /* copy the request */
653                 
654                 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
655                 
656                 if (down_req->op.mod.message == NULL) {
657                         talloc_free(mem_ctx);
658                         return LDB_ERR_OPERATIONS_ERROR;
659                 }
660                 
661                 ret = fix_attributes(module->ldb, schema, msg);
662                 if (ret != LDB_SUCCESS) {
663                         talloc_free(mem_ctx);
664                         return ret;
665                 }
666
667                 ret = objectclass_sort(module, schema, msg, mem_ctx, objectclass_element, &sorted);
668                 if (ret != LDB_SUCCESS) {
669                         return ret;
670                 }
671
672                 /* We must completely replace the existing objectClass entry,
673                  * because we need it sorted */
674                 
675                 ldb_msg_remove_attr(msg, "objectClass");
676                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
677                 
678                 if (ret != LDB_SUCCESS) {
679                         talloc_free(mem_ctx);
680                         return ret;
681                 }
682
683                 /* Move from the linked list back into an ldb msg */
684                 for (current = sorted; current; current = current->next) {
685                         ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
686                         if (ret != LDB_SUCCESS) {
687                                 ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
688                                 talloc_free(mem_ctx);
689                                 return ret;
690                         }
691                 }
692                 
693                 talloc_free(mem_ctx);
694
695                 ret = ldb_msg_sanity_check(module->ldb, msg);
696                 if (ret != LDB_SUCCESS) {
697                         talloc_free(mem_ctx);
698                         return ret;
699                 }
700                 
701                 /* go on with the call chain */
702                 ret = ldb_next_request(module, down_req);
703                 
704                 /* do not free down_req as the call results may be linked to it,
705                  * it will be freed when the upper level request get freed */
706                 if (ret == LDB_SUCCESS) {
707                         req->handle = down_req->handle;
708                 }
709                 return ret;
710         }
711         }
712
713         /* This isn't the default branch of the switch, but a 'in any
714          * other case'.  When a delete isn't for all objectClasses for
715          * example
716          */
717         {
718                 struct ldb_handle *h;
719                 struct oc_context *ac;
720                 
721                 h = oc_init_handle(req, module);
722                 if (!h) {
723                         return LDB_ERR_OPERATIONS_ERROR;
724                 }
725                 ac = talloc_get_type(h->private_data, struct oc_context);
726                 
727                 /* return or own handle to deal with this call */
728                 req->handle = h;
729                 
730                 /* prepare the first operation */
731                 ac->down_req = talloc(ac, struct ldb_request);
732                 if (ac->down_req == NULL) {
733                         ldb_oom(ac->module->ldb);
734                         return LDB_ERR_OPERATIONS_ERROR;
735                 }
736                 
737                 *(ac->down_req) = *req; /* copy the request */
738                 
739                 ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
740                 
741                 if (ac->down_req->op.mod.message == NULL) {
742                         ldb_oom(ac->module->ldb);
743                         return LDB_ERR_OPERATIONS_ERROR;
744                 }
745                 
746                 ret = fix_attributes(ac->module->ldb, schema, msg);
747                 if (ret != LDB_SUCCESS) {
748                         ldb_oom(ac->module->ldb);
749                         return ret;
750                 }
751
752                 ac->down_req->context = NULL;
753                 ac->down_req->callback = NULL;
754                 ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
755                 
756                 ac->step = OC_DO_REQ;
757
758                 return ldb_next_request(module, ac->down_req);
759         }
760 }
761
762 static int objectclass_search_self(struct ldb_handle *h) 
763 {
764         int ret;
765         struct oc_context *ac;
766         static const char * const attrs[] = { "objectClass", NULL };
767
768         ac = talloc_get_type(h->private_data, struct oc_context);
769
770         ret = ldb_build_search_req(&ac->search_req, ac->module->ldb,
771                                    ac, ac->orig_req->op.mod.message->dn, LDB_SCOPE_BASE,
772                                    "(objectClass=*)",
773                                    attrs, NULL, 
774                                    ac, get_search_callback);
775
776         if (ret != LDB_SUCCESS) {
777                 return ret;
778         }
779
780         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
781
782         ac->step = OC_SEARCH_SELF;
783
784         return ldb_next_request(ac->module, ac->search_req);
785 }
786
787 static int objectclass_do_mod(struct ldb_handle *h) {
788
789         const struct dsdb_schema *schema;
790         struct oc_context *ac;
791         struct ldb_message_element *objectclass_element;
792         struct ldb_message *msg;
793         TALLOC_CTX *mem_ctx;
794         struct class_list *sorted, *current;
795         int ret;
796       
797         ac = talloc_get_type(h->private_data, struct oc_context);
798         schema = dsdb_get_schema(ac->module->ldb);
799
800         mem_ctx = talloc_new(ac);
801         if (mem_ctx == NULL) {
802                 return LDB_ERR_OPERATIONS_ERROR;
803         }
804
805         ac->mod_req = talloc(ac, struct ldb_request);
806         if (ac->mod_req == NULL) {
807                 talloc_free(mem_ctx);
808                 return LDB_ERR_OPERATIONS_ERROR;
809         }
810
811         ac->mod_req->operation = LDB_MODIFY;
812         ac->mod_req->controls = NULL;
813         ac->mod_req->context = ac;
814         ac->mod_req->callback = NULL;
815         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
816         
817         /* use a new message structure */
818         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
819         if (msg == NULL) {
820                 ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
821                 talloc_free(mem_ctx);
822                 return LDB_ERR_OPERATIONS_ERROR;
823         }
824
825         /* This is now the objectClass list from the database */
826         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
827                                                    "objectClass");
828         if (!objectclass_element) {
829                 /* Where did it go?  bail now... */
830                 talloc_free(mem_ctx);
831                 return LDB_ERR_OPERATIONS_ERROR;
832         }
833         
834         /* modify dn */
835         msg->dn = ac->orig_req->op.mod.message->dn;
836
837         ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
838         if (ret != LDB_SUCCESS) {
839                 return ret;
840         }
841
842         /* We must completely replace the existing objectClass entry.
843          * We could do a constrained add/del, but we are meant to be
844          * in a transaction... */
845
846         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
847         if (ret != LDB_SUCCESS) {
848                 ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
849                 talloc_free(mem_ctx);
850                 return ret;
851         }
852         
853         /* Move from the linked list back into an ldb msg */
854         for (current = sorted; current; current = current->next) {
855                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
856                 if (ret != LDB_SUCCESS) {
857                         ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
858                         talloc_free(mem_ctx);
859                         return ret;
860                 }
861         }
862
863         ret = ldb_msg_sanity_check(ac->module->ldb, msg);
864         if (ret != LDB_SUCCESS) {
865                 talloc_free(mem_ctx);
866                 return ret;
867         }
868
869
870         h->state = LDB_ASYNC_INIT;
871         h->status = LDB_SUCCESS;
872
873         ac->step = OC_DO_MOD;
874
875         talloc_free(mem_ctx);
876         /* perform the search */
877         return ldb_next_request(ac->module, ac->mod_req);
878 }
879
880 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
881 {
882
883         static const char * const attrs[] = { NULL };
884
885         struct ldb_handle *h;
886         struct oc_context *ac;
887         struct ldb_dn *parent_dn;
888         int ret;
889         
890         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
891
892         if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
893                 return ldb_next_request(module, req);
894         }
895         
896         /* Firstly ensure we are not trying to rename it to be a child of itself */
897         if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
898             && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
899                 ldb_asprintf_errstring(module->ldb, "Cannot rename %s to be a child of itself",
900                                        ldb_dn_get_linearized(req->op.rename.olddn));
901                 return LDB_ERR_UNWILLING_TO_PERFORM;
902         }
903
904         h = oc_init_handle(req, module);
905         if (!h) {
906                 return LDB_ERR_OPERATIONS_ERROR;
907         }
908         ac = talloc_get_type(h->private_data, struct oc_context);
909         
910         /* return or own handle to deal with this call */
911         req->handle = h;
912
913         parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.rename.newdn);
914         if (parent_dn == NULL) {
915                 ldb_oom(module->ldb);
916                 return LDB_ERR_OPERATIONS_ERROR;
917         }
918         ret = ldb_build_search_req(&ac->search_req, module->ldb,
919                                    ac, parent_dn, LDB_SCOPE_BASE,
920                                    "(objectClass=*)",
921                                    attrs, NULL, 
922                                    ac, get_search_callback);
923         if (ret != LDB_SUCCESS) {
924                 return ret;
925         }
926         talloc_steal(ac->search_req, parent_dn);
927         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
928
929         ac->step = OC_SEARCH_RENAME_PARENT;
930
931         return ldb_next_request(ac->module, ac->search_req);
932 }
933
934 static int objectclass_do_rename(struct ldb_handle *h) 
935 {
936         struct oc_context *ac;
937         int ret;
938       
939         ac = talloc_get_type(h->private_data, struct oc_context);
940
941         ac->rename_req = talloc(ac, struct ldb_request);
942         if (ac->rename_req == NULL) {
943                 return LDB_ERR_OPERATIONS_ERROR;
944         }
945
946         *ac->rename_req = *ac->orig_req;
947
948         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->rename_req);
949         
950         /* Check we have a valid parent */
951         if (ac->search_res == NULL) {
952                 ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot rename %s, parent does not exist!", 
953                                        ldb_dn_get_linearized(ac->orig_req->op.rename.newdn));
954                 return LDB_ERR_UNWILLING_TO_PERFORM;
955         }
956         
957         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
958         ret = fix_dn(ac->rename_req, 
959                      ac->orig_req->op.rename.newdn, 
960                      ac->search_res->message->dn, 
961                      &ac->rename_req->op.rename.newdn);
962
963         if (ret != LDB_SUCCESS) {
964                 return ret;
965         }
966
967         /* TODO: Check this is a valid child to this parent,
968          * by reading the allowedChildClasses and
969          * allowedChildClasssesEffective attributes */
970
971         h->state = LDB_ASYNC_INIT;
972         h->status = LDB_SUCCESS;
973
974         ac->step = OC_DO_RENAME;
975
976         /* perform the rename */
977         return ldb_next_request(ac->module, ac->rename_req);
978 }
979
980 static int oc_wait(struct ldb_handle *handle) {
981         struct oc_context *ac;
982         int ret;
983     
984         if (!handle || !handle->private_data) {
985                 return LDB_ERR_OPERATIONS_ERROR;
986         }
987
988         if (handle->state == LDB_ASYNC_DONE) {
989                 return handle->status;
990         }
991
992         handle->state = LDB_ASYNC_PENDING;
993         handle->status = LDB_SUCCESS;
994
995         ac = talloc_get_type(handle->private_data, struct oc_context);
996
997         switch (ac->step) {
998         case OC_DO_REQ:
999                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
1000
1001                 if (ret != LDB_SUCCESS) {
1002                         handle->status = ret;
1003                         goto done;
1004                 }
1005                 if (ac->down_req->handle->status != LDB_SUCCESS) {
1006                         handle->status = ac->down_req->handle->status;
1007                         goto done;
1008                 }
1009
1010                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
1011                         return LDB_SUCCESS;
1012                 }
1013
1014                 /* mods done, go on */
1015                 return objectclass_search_self(handle);
1016
1017         case OC_SEARCH_SELF:
1018                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
1019
1020                 if (ret != LDB_SUCCESS) {
1021                         handle->status = ret;
1022                         goto done;
1023                 }
1024                 if (ac->search_req->handle->status != LDB_SUCCESS) {
1025                         handle->status = ac->search_req->handle->status;
1026                         goto done;
1027                 }
1028
1029                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
1030                         return LDB_SUCCESS;
1031                 }
1032
1033                 /* self search done, go on */
1034                 return objectclass_do_mod(handle);
1035
1036         case OC_DO_MOD:
1037                 ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
1038
1039                 if (ret != LDB_SUCCESS) {
1040                         handle->status = ret;
1041                         goto done;
1042                 }
1043                 if (ac->mod_req->handle->status != LDB_SUCCESS) {
1044                         handle->status = ac->mod_req->handle->status;
1045                         goto done;
1046                 }
1047
1048                 if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
1049                         return LDB_SUCCESS;
1050                 }
1051
1052                 break;
1053                 
1054         case OC_SEARCH_ADD_PARENT:
1055                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
1056
1057                 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
1058                         handle->status = ret;
1059                         goto done;
1060                 }
1061                 if (ac->search_req->handle->status != LDB_SUCCESS
1062                     && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
1063                         handle->status = ac->search_req->handle->status;
1064                         goto done;
1065                 }
1066
1067                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
1068                         return LDB_SUCCESS;
1069                 }
1070
1071                 /* parent search done, go on */
1072                 return objectclass_do_add(handle);
1073
1074         case OC_DO_ADD:
1075                 ret = ldb_wait(ac->add_req->handle, LDB_WAIT_NONE);
1076
1077                 if (ret != LDB_SUCCESS) {
1078                         handle->status = ret;
1079                         goto done;
1080                 }
1081                 if (ac->add_req->handle->status != LDB_SUCCESS) {
1082                         handle->status = ac->add_req->handle->status;
1083                         goto done;
1084                 }
1085
1086                 if (ac->add_req->handle->state != LDB_ASYNC_DONE) {
1087                         return LDB_SUCCESS;
1088                 }
1089
1090                 break;
1091                 
1092         case OC_SEARCH_RENAME_PARENT:
1093                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
1094
1095                 if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
1096                         handle->status = ret;
1097                         goto done;
1098                 }
1099                 if (ac->search_req->handle->status != LDB_SUCCESS && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
1100                         handle->status = ac->search_req->handle->status;
1101                         goto done;
1102                 }
1103
1104                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
1105                         return LDB_SUCCESS;
1106                 }
1107
1108                 /* parent search done, go on */
1109                 return objectclass_do_rename(handle);
1110
1111         case OC_DO_RENAME:
1112                 ret = ldb_wait(ac->rename_req->handle, LDB_WAIT_NONE);
1113
1114                 if (ret != LDB_SUCCESS) {
1115                         handle->status = ret;
1116                         goto done;
1117                 }
1118                 if (ac->rename_req->handle->status != LDB_SUCCESS) {
1119                         handle->status = ac->rename_req->handle->status;
1120                         goto done;
1121                 }
1122
1123                 if (ac->rename_req->handle->state != LDB_ASYNC_DONE) {
1124                         return LDB_SUCCESS;
1125                 }
1126
1127                 break;
1128                 
1129         default:
1130                 ret = LDB_ERR_OPERATIONS_ERROR;
1131                 goto done;
1132         }
1133
1134         ret = LDB_SUCCESS;
1135
1136 done:
1137         handle->state = LDB_ASYNC_DONE;
1138         return ret;
1139 }
1140
1141 static int oc_wait_all(struct ldb_handle *handle) {
1142
1143         int ret;
1144
1145         while (handle->state != LDB_ASYNC_DONE) {
1146                 ret = oc_wait(handle);
1147                 if (ret != LDB_SUCCESS) {
1148                         return ret;
1149                 }
1150         }
1151
1152         return handle->status;
1153 }
1154
1155 static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1156 {
1157         if (type == LDB_WAIT_ALL) {
1158                 return oc_wait_all(handle);
1159         } else {
1160                 return oc_wait(handle);
1161         }
1162 }
1163
1164 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1165         .name              = "objectclass",
1166         .add           = objectclass_add,
1167         .modify        = objectclass_modify,
1168         .rename        = objectclass_rename,
1169         .wait          = objectclass_wait
1170 };