s4-dsdb: fix handling of AUX classes in objectclass_sort
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2006-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
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_module.h"
38 #include "dlinklist.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "librpc/ndr/libndr.h"
41 #include "librpc/gen_ndr/ndr_security.h"
42 #include "libcli/security/security.h"
43 #include "auth/auth.h"
44 #include "param/param.h"
45 #include "../libds/common/flags.h"
46 #include "util.h"
47
48 struct oc_context {
49
50         struct ldb_module *module;
51         struct ldb_request *req;
52
53         struct ldb_reply *search_res;
54
55         int (*step_fn)(struct oc_context *);
56 };
57
58 struct class_list {
59         struct class_list *prev, *next;
60         const struct dsdb_class *objectclass;
61 };
62
63 static struct oc_context *oc_init_context(struct ldb_module *module,
64                                           struct ldb_request *req)
65 {
66         struct ldb_context *ldb;
67         struct oc_context *ac;
68
69         ldb = ldb_module_get_ctx(module);
70
71         ac = talloc_zero(req, struct oc_context);
72         if (ac == NULL) {
73                 ldb_set_errstring(ldb, "Out of Memory");
74                 return NULL;
75         }
76
77         ac->module = module;
78         ac->req = req;
79
80         return ac;
81 }
82
83 static int objectclass_do_add(struct oc_context *ac);
84
85 /* Sort objectClasses into correct order, and validate that all
86  * objectClasses specified actually exist in the schema
87  */
88
89 static int objectclass_sort(struct ldb_module *module,
90                             const struct dsdb_schema *schema,
91                             TALLOC_CTX *mem_ctx,
92                             struct ldb_message_element *objectclass_element,
93                             struct class_list **sorted_out) 
94 {
95         struct ldb_context *ldb;
96         int i, lowest;
97         struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
98
99         ldb = ldb_module_get_ctx(module);
100
101         /* DESIGN:
102          *
103          * We work on 4 different 'bins' (implemented here as linked lists):
104          *
105          * * sorted:       the eventual list, in the order we wish to push
106          *                 into the database.  This is the only ordered list.
107          *
108          * * parent_class: The current parent class 'bin' we are
109          *                 trying to find subclasses for
110          *
111          * * subclass:     The subclasses we have found so far
112          *
113          * * unsorted:     The remaining objectClasses
114          *
115          * The process is a matter of filtering objectClasses up from
116          * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
117          * 
118          * We start with 'top' (found and promoted to parent_class
119          * initially).  Then we find (in unsorted) all the direct
120          * subclasses of 'top'.  parent_classes is concatenated onto
121          * the end of 'sorted', and subclass becomes the list in
122          * parent_class.
123          *
124          * We then repeat, until we find no more subclasses.  Any left
125          * over classes are added to the end.
126          *
127          */
128
129         /* Firstly, dump all the objectClass elements into the
130          * unsorted bin, except for 'top', which is special */
131         for (i=0; i < objectclass_element->num_values; i++) {
132                 current = talloc(mem_ctx, struct class_list);
133                 if (!current) {
134                         ldb_oom(ldb);
135                         return LDB_ERR_OPERATIONS_ERROR;
136                 }
137                 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
138                 if (!current->objectclass) {
139                         ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema", 
140                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
141                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
142                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
143                 } else if (current->objectclass->isDefunct) {
144                         ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects", 
145                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
147                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
148                 }
149
150                 /* Don't add top to list, we will do that later */
151                 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
152                         DLIST_ADD_END(unsorted, current, struct class_list *);
153                 }
154         }
155
156         /* Add top here, to prevent duplicates */
157         current = talloc(mem_ctx, struct class_list);
158         current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
159         DLIST_ADD_END(sorted, current, struct class_list *);
160
161
162         /* For each object:  find parent chain */
163         for (current = unsorted; schema && current; current = current->next) {
164                 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
165                         if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
166                                 break;
167                         }
168                 }
169                 /* If we didn't get to the end of the list, we need to add this parent */
170                 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
171                         continue;
172                 }
173
174                 new_parent = talloc(mem_ctx, struct class_list);
175                 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
176                 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
177         }
178
179         do
180         {
181                 lowest = INT_MAX;
182                 current_lowest = NULL;
183                 for (current = unsorted; schema && current; current = current->next) {
184                         if(current->objectclass->subClass_order < lowest) {
185                                 current_lowest = current;
186                                 lowest = current->objectclass->subClass_order;
187                         }
188                 }
189
190                 if(current_lowest != NULL) {
191                         DLIST_REMOVE(unsorted,current_lowest);
192                         DLIST_ADD_END(sorted,current_lowest, struct class_list *);
193                 }
194         } while(unsorted);
195
196
197         if (!unsorted) {
198                 *sorted_out = sorted;
199                 return LDB_SUCCESS;
200         }
201
202         if (!schema) {
203                 /* If we don't have schema yet, then just merge the lists again */
204                 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
205                 *sorted_out = sorted;
206                 return LDB_SUCCESS;
207         }
208
209         /* This shouldn't happen, and would break MMC, perhaps there
210          * was no 'top', a conflict in the objectClasses or some other
211          * schema error?
212          */
213         ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
214         return LDB_ERR_OBJECT_CLASS_VIOLATION;
215 }
216
217 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
218 {
219         struct ldb_context *ldb;
220         struct oc_context *ac;
221         int ret;
222
223         ac = talloc_get_type(req->context, struct oc_context);
224         ldb = ldb_module_get_ctx(ac->module);
225
226         if (!ares) {
227                 return ldb_module_done(ac->req, NULL, NULL,
228                                         LDB_ERR_OPERATIONS_ERROR);
229         }
230         if (ares->error != LDB_SUCCESS &&
231             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
232                 return ldb_module_done(ac->req, ares->controls,
233                                         ares->response, ares->error);
234         }
235
236         ldb_reset_err_string(ldb);
237
238         switch (ares->type) {
239         case LDB_REPLY_ENTRY:
240                 if (ac->search_res != NULL) {
241                         ldb_set_errstring(ldb, "Too many results");
242                         talloc_free(ares);
243                         return ldb_module_done(ac->req, NULL, NULL,
244                                                 LDB_ERR_OPERATIONS_ERROR);
245                 }
246
247                 ac->search_res = talloc_steal(ac, ares);
248                 break;
249
250         case LDB_REPLY_REFERRAL:
251                 /* ignore */
252                 talloc_free(ares);
253                 break;
254
255         case LDB_REPLY_DONE:
256                 talloc_free(ares);
257                 ret = ac->step_fn(ac);
258                 if (ret != LDB_SUCCESS) {
259                         return ldb_module_done(ac->req, NULL, NULL, ret);
260                 }
261                 break;
262         }
263
264         return LDB_SUCCESS;
265 }
266
267 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
268 {
269         struct oc_context *ac;
270
271         ac = talloc_get_type(req->context, struct oc_context);
272
273         if (!ares) {
274                 return ldb_module_done(ac->req, NULL, NULL,
275                                         LDB_ERR_OPERATIONS_ERROR);
276         }
277         if (ares->error != LDB_SUCCESS) {
278                 return ldb_module_done(ac->req, ares->controls,
279                                         ares->response, ares->error);
280         }
281
282         if (ares->type != LDB_REPLY_DONE) {
283                 talloc_free(ares);
284                 return ldb_module_done(ac->req, NULL, NULL,
285                                         LDB_ERR_OPERATIONS_ERROR);
286         }
287
288         return ldb_module_done(ac->req, ares->controls,
289                                 ares->response, ares->error);
290 }
291
292 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
293
294    This should mean that if the parent is:
295     CN=Users,DC=samba,DC=example,DC=com
296    and a proposed child is
297     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
298
299    The resulting DN should be:
300
301     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
302    
303  */
304 static int fix_dn(TALLOC_CTX *mem_ctx, 
305                   struct ldb_dn *newdn, struct ldb_dn *parent_dn, 
306                   struct ldb_dn **fixed_dn) 
307 {
308         char *upper_rdn_attr;
309         const struct ldb_val *rdn_val;
310
311         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
312         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
313
314         /* We need the attribute name in upper case */
315         upper_rdn_attr = strupper_talloc(*fixed_dn, 
316                                          ldb_dn_get_rdn_name(newdn));
317         if (!upper_rdn_attr) {
318                 return LDB_ERR_OPERATIONS_ERROR;
319         }
320
321         /* Create a new child */
322         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
323                 return LDB_ERR_OPERATIONS_ERROR;
324         }
325
326
327         rdn_val = ldb_dn_get_rdn_val(newdn);
328
329 #if 0
330         /* the rules for rDN length constraints are more complex than
331         this. Until we understand them we need to leave this
332         constraint out. Otherwise we break replication, as windows
333         does sometimes send us rDNs longer than 64 */
334         if (!rdn_val || rdn_val->length > 64) {
335                 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
336         }
337 #endif
338
339
340         /* And replace it with CN=foo (we need the attribute in upper case */
341         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
342 }
343
344 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
345 static int fix_check_attributes(struct ldb_context *ldb,
346                                 const struct dsdb_schema *schema,
347                                 struct ldb_message *msg,
348                                 enum ldb_request_type op)
349 {
350         unsigned int i;
351         for (i=0; i < msg->num_elements; i++) {
352                 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
353                 /* Add in a very special case for 'clearTextPassword',
354                  * which is used for internal processing only, and is
355                  * not presented in the schema */
356                 if (!attribute) {
357                         if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
358                                 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
359                                 /* Apparently Windows sends exactly this behaviour */
360                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
361                         }
362                 } else {
363                         msg->elements[i].name = attribute->lDAPDisplayName;
364
365                         /* We have to deny write operations on constructed attributes */
366                         if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
367                                 if (op == LDB_ADD) {
368                                         return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
369                                 } else {
370                                         return LDB_ERR_CONSTRAINT_VIOLATION;
371                                 }
372                         }
373
374                 }
375         }
376
377         return LDB_SUCCESS;
378 }
379
380 static int objectclass_do_add(struct oc_context *ac);
381
382 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
383 {
384         struct ldb_context *ldb;
385         struct ldb_request *search_req;
386         struct oc_context *ac;
387         struct ldb_dn *parent_dn;
388         int ret;
389         static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
390
391         ldb = ldb_module_get_ctx(module);
392
393         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
394
395         /* do not manipulate our control entries */
396         if (ldb_dn_is_special(req->op.add.message->dn)) {
397                 return ldb_next_request(module, req);
398         }
399
400         /* the objectClass must be specified on add */
401         if (ldb_msg_find_element(req->op.add.message, 
402                                  "objectClass") == NULL) {
403                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
404         }
405
406         ac = oc_init_context(module, req);
407         if (ac == NULL) {
408                 return LDB_ERR_OPERATIONS_ERROR;
409         }
410
411         /* If there isn't a parent, just go on to the add processing */
412         if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
413                 return objectclass_do_add(ac);
414         }
415
416         /* get copy of parent DN */
417         parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
418         if (parent_dn == NULL) {
419                 ldb_oom(ldb);
420                 return LDB_ERR_OPERATIONS_ERROR;
421         }
422
423         ret = ldb_build_search_req(&search_req, ldb,
424                                    ac, parent_dn, LDB_SCOPE_BASE,
425                                    "(objectClass=*)", parent_attrs,
426                                    NULL,
427                                    ac, get_search_callback,
428                                    req);
429         if (ret != LDB_SUCCESS) {
430                 return ret;
431         }
432         talloc_steal(search_req, parent_dn);
433
434         ac->step_fn = objectclass_do_add;
435
436         return ldb_next_request(ac->module, search_req);
437 }
438
439 static int objectclass_do_add(struct oc_context *ac)
440 {
441         struct ldb_context *ldb;
442         const struct dsdb_schema *schema;
443         struct ldb_request *add_req;
444         char *value;
445         struct ldb_message_element *objectclass_element, *el;
446         struct ldb_message *msg;
447         TALLOC_CTX *mem_ctx;
448         struct class_list *sorted, *current;
449         int ret;
450         const struct dsdb_class *objectclass;
451         int32_t systemFlags = 0;
452         const char *rdn_name = NULL;
453
454         ldb = ldb_module_get_ctx(ac->module);
455         schema = dsdb_get_schema(ldb);
456
457         mem_ctx = talloc_new(ac);
458         if (mem_ctx == NULL) {
459                 return LDB_ERR_OPERATIONS_ERROR;
460         }
461
462         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
463
464         /* Check we have a valid parent */
465         if (ac->search_res == NULL) {
466                 if (ldb_dn_compare(ldb_get_root_basedn(ldb),
467                                                                 msg->dn) == 0) {
468                         /* Allow the tree to be started */
469                         
470                         /* but don't keep any error string, it's meaningless */
471                         ldb_set_errstring(ldb, NULL);
472                 } else {
473                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
474                                                ldb_dn_get_linearized(msg->dn));
475                         talloc_free(mem_ctx);
476                         return LDB_ERR_NO_SUCH_OBJECT;
477                 }
478         } else {
479
480                 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
481                 ret = fix_dn(msg, 
482                              ac->req->op.add.message->dn,
483                              ac->search_res->message->dn,
484                              &msg->dn);
485
486                 if (ret != LDB_SUCCESS) {
487                         ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form", 
488                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
489                         talloc_free(mem_ctx);
490                         return ret;
491                 }
492
493         }
494         if (schema) {
495                 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
496                 if (ret != LDB_SUCCESS) {
497                         talloc_free(mem_ctx);
498                         return ret;
499                 }
500
501                 /* This is now the objectClass list from the database */
502                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
503
504                 if (!objectclass_element) {
505                         /* Where did it go?  bail now... */
506                         talloc_free(mem_ctx);
507                         return LDB_ERR_OPERATIONS_ERROR;
508                 }
509                 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
510                 if (ret != LDB_SUCCESS) {
511                         talloc_free(mem_ctx);
512                         return ret;
513                 }
514                 
515                 ldb_msg_remove_attr(msg, "objectClass");
516                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
517                 
518                 if (ret != LDB_SUCCESS) {
519                         talloc_free(mem_ctx);
520                         return ret;
521                 }
522
523                 /* We must completely replace the existing objectClass entry,
524                  * because we need it sorted */
525
526                 /* Move from the linked list back into an ldb msg */
527                 for (current = sorted; current; current = current->next) {
528                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
529                         if (value == NULL) {
530                                 ldb_oom(ldb);
531                                 talloc_free(mem_ctx);
532                                 return LDB_ERR_OPERATIONS_ERROR;
533                         }
534                         ret = ldb_msg_add_string(msg, "objectClass", value);
535                         if (ret != LDB_SUCCESS) {
536                                 ldb_set_errstring(ldb,
537                                                   "objectclass: could not re-add sorted "
538                                                   "objectclass to modify msg");
539                                 talloc_free(mem_ctx);
540                                 return ret;
541                         }
542                 }
543
544                 /* Retrive the message again so get_last_structural_class works */
545                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
546
547                 /* Make sure its valid to add an object of this type */
548                 objectclass = get_last_structural_class(schema,objectclass_element);
549                 if(objectclass == NULL) {
550                         ldb_asprintf_errstring(ldb,
551                                                 "Failed to find a structural class for %s",
552                                                   ldb_dn_get_linearized(msg->dn));
553                         return LDB_ERR_NAMING_VIOLATION;
554                 }
555
556                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
557                 if (objectclass->rDNAttID
558                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
559                         ldb_asprintf_errstring(ldb,
560                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
561                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
562                         return LDB_ERR_NAMING_VIOLATION;
563                 }
564
565                 if (ac->search_res && ac->search_res->message) {
566                         struct ldb_message_element *oc_el
567                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
568
569                         bool allowed_class = false;
570                         int i, j;
571                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
572                                 const struct dsdb_class *sclass;
573
574                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
575                                 if (!sclass) {
576                                         /* We don't know this class?  what is going on? */
577                                         continue;
578                                 }
579                                 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
580                                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
581                                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
582                                                         allowed_class = true;
583                                                         break;
584                                                 }
585                                         }
586                                 } else {
587                                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
588                                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
589                                                         allowed_class = true;
590                                                         break;
591                                                 }
592                                         }
593                                 }
594                         }
595
596                         if (!allowed_class) {
597                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
598                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
599                                 return LDB_ERR_NAMING_VIOLATION;
600                         }
601                 }
602
603                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
604                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
605                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
606                         return LDB_ERR_UNWILLING_TO_PERFORM;
607                 }
608
609                 if (!ldb_msg_find_element(msg, "objectCategory")) {
610                         struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
611                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
612                                 /* Strip off extended components */
613                                 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
614                                 value = ldb_dn_alloc_linearized(msg, dn);
615                                 talloc_free(dn);
616                         } else {
617                                 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
618                         }
619                         if (value == NULL) {
620                                 ldb_oom(ldb);
621                                 talloc_free(mem_ctx);
622                                 return LDB_ERR_OPERATIONS_ERROR;
623                         }
624                         ldb_msg_add_string(msg, "objectCategory", value);
625                 }
626                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
627                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
628                                                 "TRUE");
629                 }
630
631                 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
632                 el = ldb_msg_find_element(msg, "systemFlags");
633
634                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
635
636                 if (el) {
637                         /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
638                         /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
639                         ldb_msg_remove_element(msg, el);
640                 }
641
642                 /* This flag is only allowed on attributeSchema objects */
643                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
644                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
645                 }
646
647                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
648                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
649                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
650                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
651                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
652                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
653
654                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
655                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
656                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
657                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
658                 }
659
660                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
661
662                 if (el || systemFlags != 0) {
663                         samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
664                 }
665         }
666
667         talloc_free(mem_ctx);
668         ret = ldb_msg_sanity_check(ldb, msg);
669
670
671         if (ret != LDB_SUCCESS) {
672                 return ret;
673         }
674
675         ret = ldb_build_add_req(&add_req, ldb, ac,
676                                 msg,
677                                 ac->req->controls,
678                                 ac, oc_op_callback,
679                                 ac->req);
680         if (ret != LDB_SUCCESS) {
681                 return ret;
682         }
683
684         /* perform the add */
685         return ldb_next_request(ac->module, add_req);
686 }
687
688 static int oc_modify_callback(struct ldb_request *req,
689                                 struct ldb_reply *ares);
690 static int objectclass_do_mod(struct oc_context *ac);
691
692 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
693 {
694         struct ldb_context *ldb = ldb_module_get_ctx(module);
695         struct ldb_message_element *objectclass_element;
696         struct ldb_message *msg;
697         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
698         struct class_list *sorted, *current;
699         struct ldb_request *down_req;
700         struct oc_context *ac;
701         TALLOC_CTX *mem_ctx;
702         char *value;
703         int ret;
704
705         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
706
707         /* do not manipulate our control entries */
708         if (ldb_dn_is_special(req->op.mod.message->dn)) {
709                 return ldb_next_request(module, req);
710         }
711         
712         /* Without schema, there isn't much to do here */
713         if (!schema) {
714                 return ldb_next_request(module, req);
715         }
716
717         /* As with the "real" AD we don't accept empty messages */
718         if (req->op.mod.message->num_elements == 0) {
719                 ldb_set_errstring(ldb, "objectclass: modify message must have "
720                                        "elements/attributes!");
721                 return LDB_ERR_UNWILLING_TO_PERFORM;
722         }
723
724         ac = oc_init_context(module, req);
725         if (ac == NULL) {
726                 return LDB_ERR_OPERATIONS_ERROR;
727         }
728
729         /* If no part of this touches the objectClass, then we don't
730          * need to make any changes.  */
731         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
732
733         /* If the only operation is the deletion of the objectClass
734          * then go on with just fixing the attribute case */
735         if (!objectclass_element) {
736                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
737                 if (msg == NULL) {
738                         return LDB_ERR_OPERATIONS_ERROR;
739                 }
740                 
741                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
742                 if (ret != LDB_SUCCESS) {
743                         return ret;
744                 }
745
746                 ret = ldb_build_mod_req(&down_req, ldb, ac,
747                                         msg,
748                                         req->controls,
749                                         ac, oc_op_callback,
750                                         req);
751                 if (ret != LDB_SUCCESS) {
752                         return ret;
753                 }
754
755                 /* go on with the call chain */
756                 return ldb_next_request(module, down_req);
757         }
758
759         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
760         case LDB_FLAG_MOD_DELETE:
761                 if (objectclass_element->num_values == 0) {
762                         return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
763                 }
764                 break;
765
766         case LDB_FLAG_MOD_REPLACE:
767                 mem_ctx = talloc_new(ac);
768                 if (mem_ctx == NULL) {
769                         return LDB_ERR_OPERATIONS_ERROR;
770                 }
771
772                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
773                 if (msg == NULL) {
774                         talloc_free(mem_ctx);
775                         return LDB_ERR_OPERATIONS_ERROR;
776                 }
777
778                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
779                 if (ret != LDB_SUCCESS) {
780                         talloc_free(mem_ctx);
781                         return ret;
782                 }
783
784                 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
785                 if (ret != LDB_SUCCESS) {
786                         talloc_free(mem_ctx);
787                         return ret;
788                 }
789
790                 /* We must completely replace the existing objectClass entry,
791                  * because we need it sorted */
792                 
793                 ldb_msg_remove_attr(msg, "objectClass");
794                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
795                 
796                 if (ret != LDB_SUCCESS) {
797                         talloc_free(mem_ctx);
798                         return ret;
799                 }
800
801                 /* Move from the linked list back into an ldb msg */
802                 for (current = sorted; current; current = current->next) {
803                         /* copy the value as this string is on the schema
804                          * context and we can't rely on it not changing
805                          * before the operation is over */
806                         value = talloc_strdup(msg,
807                                         current->objectclass->lDAPDisplayName);
808                         if (value == NULL) {
809                                 ldb_oom(ldb);
810                                 talloc_free(mem_ctx);
811                                 return LDB_ERR_OPERATIONS_ERROR;
812                         }
813                         ret = ldb_msg_add_string(msg, "objectClass", value);
814                         if (ret != LDB_SUCCESS) {
815                                 ldb_set_errstring(ldb,
816                                         "objectclass: could not re-add sorted "
817                                         "objectclass to modify msg");
818                                 talloc_free(mem_ctx);
819                                 return ret;
820                         }
821                 }
822                 
823                 talloc_free(mem_ctx);
824
825                 ret = ldb_msg_sanity_check(ldb, msg);
826                 if (ret != LDB_SUCCESS) {
827                         return ret;
828                 }
829
830                 ret = ldb_build_mod_req(&down_req, ldb, ac,
831                                         msg,
832                                         req->controls,
833                                         ac, oc_op_callback,
834                                         req);
835                 if (ret != LDB_SUCCESS) {
836                         return ret;
837                 }
838
839                 /* go on with the call chain */
840                 return ldb_next_request(module, down_req);
841         }
842
843         /* This isn't the default branch of the switch, but a 'in any
844          * other case'.  When a delete isn't for all objectClasses for
845          * example
846          */
847
848         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
849         if (msg == NULL) {
850                 ldb_oom(ldb);
851                 return LDB_ERR_OPERATIONS_ERROR;
852         }
853
854         ret = fix_check_attributes(ldb, schema, msg, req->operation);
855         if (ret != LDB_SUCCESS) {
856                 ldb_oom(ldb);
857                 return ret;
858         }
859
860         ret = ldb_build_mod_req(&down_req, ldb, ac,
861                                 msg,
862                                 req->controls,
863                                 ac, oc_modify_callback,
864                                 req);
865         if (ret != LDB_SUCCESS) {
866                 return ret;
867         }
868
869         return ldb_next_request(module, down_req);
870 }
871
872 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
873 {
874         struct ldb_context *ldb;
875         static const char * const attrs[] = { "objectClass", NULL };
876         struct ldb_request *search_req;
877         struct oc_context *ac;
878         int ret;
879
880         ac = talloc_get_type(req->context, struct oc_context);
881         ldb = ldb_module_get_ctx(ac->module);
882
883         if (!ares) {
884                 return ldb_module_done(ac->req, NULL, NULL,
885                                         LDB_ERR_OPERATIONS_ERROR);
886         }
887         if (ares->error != LDB_SUCCESS) {
888                 return ldb_module_done(ac->req, ares->controls,
889                                         ares->response, ares->error);
890         }
891
892         if (ares->type != LDB_REPLY_DONE) {
893                 talloc_free(ares);
894                 return ldb_module_done(ac->req, NULL, NULL,
895                                         LDB_ERR_OPERATIONS_ERROR);
896         }
897
898         talloc_free(ares);
899
900         ret = ldb_build_search_req(&search_req, ldb, ac,
901                                    ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
902                                    "(objectClass=*)",
903                                    attrs, NULL, 
904                                    ac, get_search_callback,
905                                    ac->req);
906         if (ret != LDB_SUCCESS) {
907                 return ldb_module_done(ac->req, NULL, NULL, ret);
908         }
909
910         ac->step_fn = objectclass_do_mod;
911
912         ret = ldb_next_request(ac->module, search_req);
913         if (ret != LDB_SUCCESS) {
914                 return ldb_module_done(ac->req, NULL, NULL, ret);
915         }
916         return LDB_SUCCESS;
917 }
918
919 static int objectclass_do_mod(struct oc_context *ac)
920 {
921         struct ldb_context *ldb;
922         const struct dsdb_schema *schema;
923         struct ldb_request *mod_req;
924         char *value;
925         struct ldb_message_element *objectclass_element;
926         struct ldb_message *msg;
927         TALLOC_CTX *mem_ctx;
928         struct class_list *sorted, *current;
929         int ret;
930
931         ldb = ldb_module_get_ctx(ac->module);
932
933         if (ac->search_res == NULL) {
934                 return LDB_ERR_OPERATIONS_ERROR;
935         }
936         schema = dsdb_get_schema(ldb);
937
938         mem_ctx = talloc_new(ac);
939         if (mem_ctx == NULL) {
940                 return LDB_ERR_OPERATIONS_ERROR;
941         }
942
943         /* use a new message structure */
944         msg = ldb_msg_new(ac);
945         if (msg == NULL) {
946                 ldb_set_errstring(ldb,
947                         "objectclass: could not create new modify msg");
948                 talloc_free(mem_ctx);
949                 return LDB_ERR_OPERATIONS_ERROR;
950         }
951
952         /* This is now the objectClass list from the database */
953         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
954                                                    "objectClass");
955         if (!objectclass_element) {
956                 /* Where did it go?  bail now... */
957                 talloc_free(mem_ctx);
958                 return LDB_ERR_OPERATIONS_ERROR;
959         }
960         
961         /* modify dn */
962         msg->dn = ac->req->op.mod.message->dn;
963
964         ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
965         if (ret != LDB_SUCCESS) {
966                 return ret;
967         }
968
969         /* We must completely replace the existing objectClass entry.
970          * We could do a constrained add/del, but we are meant to be
971          * in a transaction... */
972
973         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
974         if (ret != LDB_SUCCESS) {
975                 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
976                 talloc_free(mem_ctx);
977                 return ret;
978         }
979         
980         /* Move from the linked list back into an ldb msg */
981         for (current = sorted; current; current = current->next) {
982                 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
983                 if (value == NULL) {
984                         ldb_oom(ldb);
985                         return LDB_ERR_OPERATIONS_ERROR;
986                 }
987                 ret = ldb_msg_add_string(msg, "objectClass", value);
988                 if (ret != LDB_SUCCESS) {
989                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
990                         talloc_free(mem_ctx);
991                         return ret;
992                 }
993         }
994
995         ret = ldb_msg_sanity_check(ldb, msg);
996         if (ret != LDB_SUCCESS) {
997                 talloc_free(mem_ctx);
998                 return ret;
999         }
1000
1001         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1002                                 msg,
1003                                 ac->req->controls,
1004                                 ac, oc_op_callback,
1005                                 ac->req);
1006         if (ret != LDB_SUCCESS) {
1007                 talloc_free(mem_ctx);
1008                 return ret;
1009         }
1010
1011         talloc_free(mem_ctx);
1012         /* perform the modify */
1013         return ldb_next_request(ac->module, mod_req);
1014 }
1015
1016 static int objectclass_do_rename(struct oc_context *ac);
1017
1018 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1019 {
1020         static const char * const attrs[] = { NULL };
1021         struct ldb_context *ldb;
1022         struct ldb_request *search_req;
1023         struct oc_context *ac;
1024         struct ldb_dn *parent_dn;
1025         int ret;
1026
1027         ldb = ldb_module_get_ctx(module);
1028
1029         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1030
1031         if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1032                 return ldb_next_request(module, req);
1033         }
1034
1035         /* Firstly ensure we are not trying to rename it to be a child of itself */
1036         if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
1037             && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1038                 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1039                                        ldb_dn_get_linearized(req->op.rename.olddn));
1040                 return LDB_ERR_UNWILLING_TO_PERFORM;
1041         }
1042
1043         ac = oc_init_context(module, req);
1044         if (ac == NULL) {
1045                 return LDB_ERR_OPERATIONS_ERROR;
1046         }
1047
1048         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1049         if (parent_dn == NULL) {
1050                 ldb_oom(ldb);
1051                 return LDB_ERR_OPERATIONS_ERROR;
1052         }
1053
1054         /*
1055           it makes a search request, looking for the parent DN to fix up the new DN
1056           to a standard one, at objectclass_do_rename()
1057          */
1058         ret = ldb_build_search_req(&search_req, ldb,
1059                                    ac, parent_dn, LDB_SCOPE_BASE,
1060                                    "(objectClass=*)",
1061                                    attrs, NULL,
1062                                    ac, get_search_callback,
1063                                    req);
1064         if (ret != LDB_SUCCESS) {
1065                 return ret;
1066         }
1067
1068         /* we have to add the show deleted control, as otherwise DRS
1069            deletes will be refused as we will think the target parent
1070            does not exist */
1071         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1072
1073         if (ret != LDB_SUCCESS) {
1074                 return ret;
1075         }
1076
1077         ac->step_fn = objectclass_do_rename;
1078
1079         return ldb_next_request(ac->module, search_req);
1080
1081
1082 }
1083
1084 static int objectclass_do_rename(struct oc_context *ac)
1085 {
1086         struct ldb_context *ldb;
1087         struct ldb_request *rename_req;
1088         struct ldb_dn *fixed_dn;
1089         int ret;
1090
1091         ldb = ldb_module_get_ctx(ac->module);
1092
1093         /* Check we have a valid parent */
1094         if (ac->search_res == NULL) {
1095                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!", 
1096                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1097                 return LDB_ERR_UNWILLING_TO_PERFORM;
1098         }
1099         
1100         /* Fix up the DN to be in the standard form,
1101          * taking particular care to match the parent DN */
1102         ret = fix_dn(ac,
1103                      ac->req->op.rename.newdn,
1104                      ac->search_res->message->dn,
1105                      &fixed_dn);
1106         if (ret != LDB_SUCCESS) {
1107                 return ret;
1108         }
1109
1110         /* TODO: Check this is a valid child to this parent,
1111          * by reading the allowedChildClasses and
1112          * allowedChildClasssesEffective attributes */
1113
1114         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1115                                    ac->req->op.rename.olddn, fixed_dn,
1116                                    ac->req->controls,
1117                                    ac, oc_op_callback,
1118                                    ac->req);
1119         if (ret != LDB_SUCCESS) {
1120                 return ret;
1121         }
1122
1123         /* perform the rename */
1124         return ldb_next_request(ac->module, rename_req);
1125 }
1126
1127 static int objectclass_init(struct ldb_module *module)
1128 {
1129         struct ldb_context *ldb = ldb_module_get_ctx(module);
1130         int ret;
1131         /* Init everything else */
1132         ret = ldb_next_init(module);
1133         if (ret != LDB_SUCCESS) {
1134                 return ret;
1135         }
1136         
1137         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1138         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1139
1140         return ret;
1141 }
1142
1143 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1144         .name              = "objectclass",
1145         .add           = objectclass_add,
1146         .modify        = objectclass_modify,
1147         .rename        = objectclass_rename,
1148         .init_context  = objectclass_init
1149 };