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