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