493ecdaad401091c850307b9d36d15a8763976b2
[kai/samba-autobuild/.git] / source3 / lib / 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-2006
6
7      ** NOTE! The following LGPL license applies to the ldb
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10    
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 2 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Lesser General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public
22    License along with this library; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26 /*
27  *  Name: ldb
28  *
29  *  Component: objectClass sorting module
30  *
31  *  Description: sort the objectClass attribute into the class hierarchy
32  *
33  *  Author: Andrew Bartlett
34  */
35
36 #include "includes.h"
37 #include "ldb/include/includes.h"
38
39 struct oc_context {
40
41         enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step;
42
43         struct ldb_module *module;
44         struct ldb_request *orig_req;
45
46         struct ldb_request *down_req;
47
48         struct ldb_request *search_req;
49         struct ldb_reply *search_res;
50
51         struct ldb_request *mod_req;
52 };
53
54 struct class_list {
55         struct class_list *prev, *next;
56         const char *objectclass;
57 };
58
59 static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
60 {
61         struct oc_context *ac;
62         struct ldb_handle *h;
63
64         h = talloc_zero(req, struct ldb_handle);
65         if (h == NULL) {
66                 ldb_set_errstring(module->ldb, "Out of Memory");
67                 return NULL;
68         }
69
70         h->module = module;
71
72         ac = talloc_zero(h, struct oc_context);
73         if (ac == NULL) {
74                 ldb_set_errstring(module->ldb, "Out of Memory");
75                 talloc_free(h);
76                 return NULL;
77         }
78
79         h->private_data = (void *)ac;
80
81         h->state = LDB_ASYNC_INIT;
82         h->status = LDB_SUCCESS;
83
84         ac->module = module;
85         ac->orig_req = req;
86
87         return h;
88 }
89
90 static int objectclass_sort(struct ldb_module *module,
91                             TALLOC_CTX *mem_ctx,
92                             struct ldb_message_element *objectclass_element,
93                             struct class_list **sorted_out) 
94 {
95         int i;
96         int layer;
97         struct class_list *sorted = NULL, *parent_class = NULL,
98                 *subclass = NULL, *unsorted = NULL, *current, *poss_subclass;
99         /* DESIGN:
100          *
101          * We work on 4 different 'bins' (implemented here as linked lists):
102          *
103          * * sorted:       the eventual list, in the order we wish to push
104          *                 into the database.  This is the only ordered list.
105          *
106          * * parent_class: The current parent class 'bin' we are
107          *                 trying to find subclasses for
108          *
109          * * subclass:     The subclasses we have found so far
110          *
111          * * unsorted:     The remaining objectClasses
112          *
113          * The process is a matter of filtering objectClasses up from
114          * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
115          * 
116          * We start with 'top' (found and promoted to parent_class
117          * initially).  Then we find (in unsorted) all the direct
118          * subclasses of 'top'.  parent_classes is concatenated onto
119          * the end of 'sorted', and subclass becomes the list in
120          * parent_class.
121          *
122          * We then repeat, until we find no more subclasses.  Any left
123          * over classes are added to the end.
124          *
125          */
126
127         /* Firstly, dump all the objectClass elements into the
128          * unsorted bin, except for 'top', which is special */
129         for (i=0; i < objectclass_element->num_values; i++) {
130                 current = talloc(mem_ctx, struct class_list);
131                 if (!current) {
132                         ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list");
133                         talloc_free(mem_ctx);
134                         return LDB_ERR_OPERATIONS_ERROR;
135                 }
136                 current->objectclass = (const char *)objectclass_element->values[i].data;
137
138                 /* this is the root of the tree.  We will start
139                  * looking for subclasses from here */
140                 if (ldb_attr_cmp("top", current->objectclass) == 0) {
141                         DLIST_ADD(parent_class, current);
142                 } else {
143                         DLIST_ADD(unsorted, current);
144                 }
145         }
146
147         /* DEBUGGING aid:  how many layers are we down now? */
148         layer = 0;
149         do {
150                 layer++;
151                 /* Find all the subclasses of classes in the
152                  * parent_classes.  Push them onto the subclass list */
153
154                 /* Ensure we don't bother if there are no unsorted entries left */
155                 for (current = parent_class; unsorted && current; current = current->next) {
156                         const char **subclasses = ldb_subclass_list(module->ldb, current->objectclass);
157
158                         /* Walk the list of possible subclasses in unsorted */
159                         for (poss_subclass = unsorted; poss_subclass; ) {
160                                 struct class_list *next;
161                                 
162                                 /* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
163                                 next = poss_subclass->next;
164
165                                 for (i = 0; subclasses && subclasses[i]; i++) {
166                                         if (ldb_attr_cmp(poss_subclass->objectclass, subclasses[i]) == 0) {
167                                                 DLIST_REMOVE(unsorted, poss_subclass);
168                                                 DLIST_ADD(subclass, poss_subclass);
169
170                                                 break;
171                                         }
172                                 }
173                                 poss_subclass = next;
174                         }
175                 }
176
177                 /* Now push the parent_classes as sorted, we are done with
178                 these.  Add to the END of the list by concatenation */
179                 DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
180
181                 /* and now find subclasses of these */
182                 parent_class = subclass;
183                 subclass = NULL;
184
185                 /* If we didn't find any subclasses we will fall out
186                  * the bottom here */
187         } while (parent_class);
188
189         /* This shouldn't happen, and would break MMC, but we can't
190          * afford to loose objectClasses.  Perhaps there was no 'top',
191          * or some other schema error? 
192          *
193          * Detecting schema errors is the job of the schema module, so
194          * at this layer we just try not to loose data
195          */
196         DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
197
198         *sorted_out = sorted;
199         return LDB_SUCCESS;
200 }
201
202 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
203 {
204         struct ldb_message_element *objectclass_element;
205         struct class_list *sorted, *current;
206         struct ldb_request *down_req;
207         struct ldb_message *msg;
208         int ret;
209         TALLOC_CTX *mem_ctx;
210
211         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
212
213         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
214                 return ldb_next_request(module, req);
215         }
216         
217         objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass");
218
219         /* If no part of this add has an objectClass, then we don't
220          * need to make any changes. cn=rootdse doesn't have an objectClass */
221         if (!objectclass_element) {
222                 return ldb_next_request(module, req);
223         }
224
225         mem_ctx = talloc_new(req);
226         if (mem_ctx == NULL) {
227                 return LDB_ERR_OPERATIONS_ERROR;
228         }
229
230         ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
231         if (ret != LDB_SUCCESS) {
232                 return ret;
233         }
234
235         /* prepare the first operation */
236         down_req = talloc(req, struct ldb_request);
237         if (down_req == NULL) {
238                 ldb_set_errstring(module->ldb, "Out of memory!");
239                 talloc_free(mem_ctx);
240                 return LDB_ERR_OPERATIONS_ERROR;
241         }
242
243         *down_req = *req; /* copy the request */
244
245         down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
246
247         if (down_req->op.add.message == NULL) {
248                 talloc_free(mem_ctx);
249                 return LDB_ERR_OPERATIONS_ERROR;
250         }
251
252         ldb_msg_remove_attr(msg, "objectClass");
253         ret = ldb_msg_add_empty(msg, "objectClass", 0);
254         
255         if (ret != LDB_SUCCESS) {
256                 talloc_free(mem_ctx);
257                 return ret;
258         }
259
260         /* We must completely replace the existing objectClass entry,
261          * because we need it sorted */
262
263         /* Move from the linked list back into an ldb msg */
264         for (current = sorted; current; current = current->next) {
265                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
266                 if (ret != LDB_SUCCESS) {
267                         ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
268                         talloc_free(mem_ctx);
269                         return ret;
270                 }
271         }
272
273         talloc_free(mem_ctx);
274         ret = ldb_msg_sanity_check(module->ldb, msg);
275
276         if (ret != LDB_SUCCESS) {
277                 return ret;
278         }
279
280         /* go on with the call chain */
281         ret = ldb_next_request(module, down_req);
282
283         /* do not free down_req as the call results may be linked to it,
284          * it will be freed when the upper level request get freed */
285         if (ret == LDB_SUCCESS) {
286                 req->handle = down_req->handle;
287         }
288         return ret;
289 }
290
291 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
292 {
293         struct ldb_message_element *objectclass_element;
294         struct ldb_message *msg;
295         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
296
297         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
298                 return ldb_next_request(module, req);
299         }
300         
301         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
302
303         /* If no part of this touches the objectClass, then we don't
304          * need to make any changes.  */
305         /* If the only operation is the deletion of the objectClass then go on */
306         if (!objectclass_element) {
307                 return ldb_next_request(module, req);
308         }
309
310         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
311         case LDB_FLAG_MOD_DELETE:
312                 /* Delete everything?  Probably totally illigal, but hey! */
313                 if (objectclass_element->num_values == 0) {
314                         return ldb_next_request(module, req);
315                 }
316                 break;
317         case LDB_FLAG_MOD_REPLACE:
318         {
319                 struct ldb_request *down_req;
320                 struct class_list *sorted, *current;
321                 TALLOC_CTX *mem_ctx;
322                 int ret;
323                 mem_ctx = talloc_new(req);
324                 if (mem_ctx == NULL) {
325                         return LDB_ERR_OPERATIONS_ERROR;
326                 }
327
328                 /* prepare the first operation */
329                 down_req = talloc(req, struct ldb_request);
330                 if (down_req == NULL) {
331                         ldb_set_errstring(module->ldb, "Out of memory!");
332                         talloc_free(mem_ctx);
333                         return LDB_ERR_OPERATIONS_ERROR;
334                 }
335                 
336                 *down_req = *req; /* copy the request */
337                 
338                 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
339                 
340                 if (down_req->op.add.message == NULL) {
341                         talloc_free(mem_ctx);
342                         return LDB_ERR_OPERATIONS_ERROR;
343                 }
344                 
345                 ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
346                 if (ret != LDB_SUCCESS) {
347                         return ret;
348                 }
349
350                 /* We must completely replace the existing objectClass entry,
351                  * because we need it sorted */
352                 
353                 ldb_msg_remove_attr(msg, "objectClass");
354                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE);
355                 
356                 if (ret != LDB_SUCCESS) {
357                         talloc_free(mem_ctx);
358                         return ret;
359                 }
360
361                 /* Move from the linked list back into an ldb msg */
362                 for (current = sorted; current; current = current->next) {
363                         ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
364                         if (ret != LDB_SUCCESS) {
365                                 ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
366                                 talloc_free(mem_ctx);
367                                 return ret;
368                         }
369                 }
370                 
371                 talloc_free(mem_ctx);
372
373                 ret = ldb_msg_sanity_check(module->ldb, msg);
374                 if (ret != LDB_SUCCESS) {
375                         talloc_free(mem_ctx);
376                         return ret;
377                 }
378                 
379                 /* go on with the call chain */
380                 ret = ldb_next_request(module, down_req);
381                 
382                 /* do not free down_req as the call results may be linked to it,
383                  * it will be freed when the upper level request get freed */
384                 if (ret == LDB_SUCCESS) {
385                         req->handle = down_req->handle;
386                 }
387                 return ret;
388         }
389         }
390
391         {
392                 struct ldb_handle *h;
393                 struct oc_context *ac;
394                 
395                 h = oc_init_handle(req, module);
396                 if (!h) {
397                         return LDB_ERR_OPERATIONS_ERROR;
398                 }
399                 ac = talloc_get_type(h->private_data, struct oc_context);
400                 
401                 /* return or own handle to deal with this call */
402                 req->handle = h;
403                 
404                 /* prepare the first operation */
405                 ac->down_req = talloc(ac, struct ldb_request);
406                 if (ac->down_req == NULL) {
407                         ldb_set_errstring(module->ldb, "Out of memory!");
408                         return LDB_ERR_OPERATIONS_ERROR;
409                 }
410                 
411                 *(ac->down_req) = *req; /* copy the request */
412                 
413                 ac->down_req->context = NULL;
414                 ac->down_req->callback = NULL;
415                 ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
416                 
417                 ac->step = OC_DO_REQ;
418
419                 return ldb_next_request(module, ac->down_req);
420         }
421 }
422
423 static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
424 {
425         struct oc_context *ac;
426
427         if (!context || !ares) {
428                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
429                 return LDB_ERR_OPERATIONS_ERROR;
430         }
431
432         ac = talloc_get_type(context, struct oc_context);
433
434         /* we are interested only in the single reply (base search) we receive here */
435         if (ares->type == LDB_REPLY_ENTRY) {
436                 if (ac->search_res != NULL) {
437                         ldb_set_errstring(ldb, "Too many results");
438                         talloc_free(ares);
439                         return LDB_ERR_OPERATIONS_ERROR;
440                 }
441
442                 ac->search_res = talloc_move(ac, &ares);
443         } else {
444                 talloc_free(ares);
445         }
446
447         return LDB_SUCCESS;
448 }
449
450 static int objectclass_search_self(struct ldb_handle *h) {
451
452         struct oc_context *ac;
453         static const char * const attrs[] = { "objectClass", NULL };
454
455         ac = talloc_get_type(h->private_data, struct oc_context);
456
457         /* prepare the search operation */
458         ac->search_req = talloc_zero(ac, struct ldb_request);
459         if (ac->search_req == NULL) {
460                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
461                 return LDB_ERR_OPERATIONS_ERROR;
462         }
463
464         ac->search_req->operation = LDB_SEARCH;
465         ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
466         ac->search_req->op.search.scope = LDB_SCOPE_BASE;
467         ac->search_req->op.search.tree = ldb_parse_tree(ac->module->ldb, NULL);
468         if (ac->search_req->op.search.tree == NULL) {
469                 ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search");
470                 return LDB_ERR_OPERATIONS_ERROR;
471         }
472         ac->search_req->op.search.attrs = attrs;
473         ac->search_req->controls = NULL;
474         ac->search_req->context = ac;
475         ac->search_req->callback = get_self_callback;
476         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
477
478         ac->step = OC_SEARCH_SELF;
479
480         return ldb_next_request(ac->module, ac->search_req);
481 }
482
483 static int objectclass_do_mod(struct ldb_handle *h) {
484
485         struct oc_context *ac;
486         struct ldb_message_element *objectclass_element;
487         struct ldb_message *msg;
488         TALLOC_CTX *mem_ctx;
489         struct class_list *sorted, *current;
490         int ret;
491       
492         ac = talloc_get_type(h->private_data, struct oc_context);
493
494         mem_ctx = talloc_new(ac);
495         if (mem_ctx == NULL) {
496                 return LDB_ERR_OPERATIONS_ERROR;
497         }
498
499         ac->mod_req = talloc(ac, struct ldb_request);
500         if (ac->mod_req == NULL) {
501                 talloc_free(mem_ctx);
502                 return LDB_ERR_OPERATIONS_ERROR;
503         }
504
505         ac->mod_req->operation = LDB_MODIFY;
506         ac->mod_req->controls = NULL;
507         ac->mod_req->context = ac;
508         ac->mod_req->callback = NULL;
509         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
510         
511         /* use a new message structure */
512         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
513         if (msg == NULL) {
514                 ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
515                 talloc_free(mem_ctx);
516                 return LDB_ERR_OPERATIONS_ERROR;
517         }
518
519         /* This is now the objectClass list from the database */
520         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
521                                                    "objectClass");
522         if (!objectclass_element) {
523                 /* Where did it go?  Move along now, nothing to see here */
524                 talloc_free(mem_ctx);
525                 return LDB_SUCCESS;
526         }
527         
528         /* modify dn */
529         msg->dn = ac->orig_req->op.mod.message->dn;
530
531         ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted);
532         if (ret != LDB_SUCCESS) {
533                 return ret;
534         }
535
536         /* We must completely replace the existing objectClass entry.
537          * We could do a constrained add/del, but we are meant to be
538          * in a transaction... */
539
540         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE);
541         if (ret != LDB_SUCCESS) {
542                 ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
543                 talloc_free(mem_ctx);
544                 return ret;
545         }
546         
547         /* Move from the linked list back into an ldb msg */
548         for (current = sorted; current; current = current->next) {
549                 ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
550                 if (ret != LDB_SUCCESS) {
551                         ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
552                         talloc_free(mem_ctx);
553                         return ret;
554                 }
555         }
556
557         ret = ldb_msg_sanity_check(ac->module->ldb, msg);
558         if (ret != LDB_SUCCESS) {
559                 talloc_free(mem_ctx);
560                 return ret;
561         }
562
563
564         h->state = LDB_ASYNC_INIT;
565         h->status = LDB_SUCCESS;
566
567         ac->step = OC_DO_MOD;
568
569         talloc_free(mem_ctx);
570         /* perform the search */
571         return ldb_next_request(ac->module, ac->mod_req);
572 }
573
574 static int oc_wait(struct ldb_handle *handle) {
575         struct oc_context *ac;
576         int ret;
577     
578         if (!handle || !handle->private_data) {
579                 return LDB_ERR_OPERATIONS_ERROR;
580         }
581
582         if (handle->state == LDB_ASYNC_DONE) {
583                 return handle->status;
584         }
585
586         handle->state = LDB_ASYNC_PENDING;
587         handle->status = LDB_SUCCESS;
588
589         ac = talloc_get_type(handle->private_data, struct oc_context);
590
591         switch (ac->step) {
592         case OC_DO_REQ:
593                 ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
594
595                 if (ret != LDB_SUCCESS) {
596                         handle->status = ret;
597                         goto done;
598                 }
599                 if (ac->down_req->handle->status != LDB_SUCCESS) {
600                         handle->status = ac->down_req->handle->status;
601                         goto done;
602                 }
603
604                 if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
605                         return LDB_SUCCESS;
606                 }
607
608                 /* mods done, go on */
609                 return objectclass_search_self(handle);
610
611         case OC_SEARCH_SELF:
612                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
613
614                 if (ret != LDB_SUCCESS) {
615                         handle->status = ret;
616                         goto done;
617                 }
618                 if (ac->search_req->handle->status != LDB_SUCCESS) {
619                         handle->status = ac->search_req->handle->status;
620                         goto done;
621                 }
622
623                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
624                         return LDB_SUCCESS;
625                 }
626
627                 /* self search done, go on */
628                 return objectclass_do_mod(handle);
629
630         case OC_DO_MOD:
631                 ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
632
633                 if (ret != LDB_SUCCESS) {
634                         handle->status = ret;
635                         goto done;
636                 }
637                 if (ac->mod_req->handle->status != LDB_SUCCESS) {
638                         handle->status = ac->mod_req->handle->status;
639                         goto done;
640                 }
641
642                 if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
643                         return LDB_SUCCESS;
644                 }
645
646                 break;
647                 
648         default:
649                 ret = LDB_ERR_OPERATIONS_ERROR;
650                 goto done;
651         }
652
653         ret = LDB_SUCCESS;
654
655 done:
656         handle->state = LDB_ASYNC_DONE;
657         return ret;
658 }
659
660 static int oc_wait_all(struct ldb_handle *handle) {
661
662         int ret;
663
664         while (handle->state != LDB_ASYNC_DONE) {
665                 ret = oc_wait(handle);
666                 if (ret != LDB_SUCCESS) {
667                         return ret;
668                 }
669         }
670
671         return handle->status;
672 }
673
674 static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
675 {
676         if (type == LDB_WAIT_ALL) {
677                 return oc_wait_all(handle);
678         } else {
679                 return oc_wait(handle);
680         }
681 }
682
683 static const struct ldb_module_ops objectclass_ops = {
684         .name              = "objectclass",
685         .add           = objectclass_add,
686         .modify        = objectclass_modify,
687         .wait          = objectclass_wait
688 };
689
690 int ldb_objectclass_init(void)
691 {
692         return ldb_register_module(&objectclass_ops);
693 }
694