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