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