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