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