s4-dsdb: moved rodc schema validation to samldb.c
[samba.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         unsigned 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 = UINT_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                                 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
368                                 if (op == LDB_ADD) {
369                                         return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
370                                 } else {
371                                         return LDB_ERR_CONSTRAINT_VIOLATION;
372                                 }
373                         }
374
375                 }
376         }
377
378         return LDB_SUCCESS;
379 }
380
381 static int objectclass_do_add(struct oc_context *ac);
382
383 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
384 {
385         struct ldb_context *ldb;
386         struct ldb_request *search_req;
387         struct oc_context *ac;
388         struct ldb_dn *parent_dn;
389         int ret;
390         static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
391
392         ldb = ldb_module_get_ctx(module);
393
394         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
395
396         /* do not manipulate our control entries */
397         if (ldb_dn_is_special(req->op.add.message->dn)) {
398                 return ldb_next_request(module, req);
399         }
400
401         /* the objectClass must be specified on add */
402         if (ldb_msg_find_element(req->op.add.message, 
403                                  "objectClass") == NULL) {
404                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
405         }
406
407         ac = oc_init_context(module, req);
408         if (ac == NULL) {
409                 return LDB_ERR_OPERATIONS_ERROR;
410         }
411
412         /* If there isn't a parent, just go on to the add processing */
413         if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
414                 return objectclass_do_add(ac);
415         }
416
417         /* get copy of parent DN */
418         parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
419         if (parent_dn == NULL) {
420                 ldb_oom(ldb);
421                 return LDB_ERR_OPERATIONS_ERROR;
422         }
423
424         ret = ldb_build_search_req(&search_req, ldb,
425                                    ac, parent_dn, LDB_SCOPE_BASE,
426                                    "(objectClass=*)", parent_attrs,
427                                    NULL,
428                                    ac, get_search_callback,
429                                    req);
430         if (ret != LDB_SUCCESS) {
431                 return ret;
432         }
433         talloc_steal(search_req, parent_dn);
434
435         ac->step_fn = objectclass_do_add;
436
437         return ldb_next_request(ac->module, search_req);
438 }
439
440 static int objectclass_do_add(struct oc_context *ac)
441 {
442         struct ldb_context *ldb;
443         const struct dsdb_schema *schema;
444         struct ldb_request *add_req;
445         char *value;
446         struct ldb_message_element *objectclass_element, *el;
447         struct ldb_message *msg;
448         TALLOC_CTX *mem_ctx;
449         struct class_list *sorted, *current;
450         int ret;
451         const struct dsdb_class *objectclass;
452         int32_t systemFlags = 0;
453         const char *rdn_name = NULL;
454
455         ldb = ldb_module_get_ctx(ac->module);
456         schema = dsdb_get_schema(ldb, ac);
457
458         mem_ctx = talloc_new(ac);
459         if (mem_ctx == NULL) {
460                 ldb_oom(ldb);
461                 return LDB_ERR_OPERATIONS_ERROR;
462         }
463
464         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
465
466         /* Check we have a valid parent */
467         if (ac->search_res == NULL) {
468                 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
469                         /* Allow the tree to be started */
470                         
471                         /* but don't keep any error string, it's meaningless */
472                         ldb_set_errstring(ldb, NULL);
473                 } else {
474                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
475                                                ldb_dn_get_linearized(msg->dn));
476                         talloc_free(mem_ctx);
477                         return LDB_ERR_NO_SUCH_OBJECT;
478                 }
479         } else {
480
481                 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
482                 ret = fix_dn(msg, 
483                              ac->req->op.add.message->dn,
484                              ac->search_res->message->dn,
485                              &msg->dn);
486
487                 if (ret != LDB_SUCCESS) {
488                         ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form", 
489                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
490                         talloc_free(mem_ctx);
491                         return ret;
492                 }
493
494         }
495         if (schema) {
496                 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
497                 if (ret != LDB_SUCCESS) {
498                         talloc_free(mem_ctx);
499                         return ret;
500                 }
501
502                 /* This is now the objectClass list from the database */
503                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
504
505                 if (!objectclass_element) {
506                         /* Where did it go?  bail now... */
507                         talloc_free(mem_ctx);
508                         return LDB_ERR_OPERATIONS_ERROR;
509                 }
510                 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
511                 if (ret != LDB_SUCCESS) {
512                         talloc_free(mem_ctx);
513                         return ret;
514                 }
515                 
516                 ldb_msg_remove_attr(msg, "objectClass");
517                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
518                 
519                 if (ret != LDB_SUCCESS) {
520                         talloc_free(mem_ctx);
521                         return ret;
522                 }
523
524                 /* We must completely replace the existing objectClass entry,
525                  * because we need it sorted */
526
527                 /* Move from the linked list back into an ldb msg */
528                 for (current = sorted; current; current = current->next) {
529                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
530                         if (value == NULL) {
531                                 ldb_oom(ldb);
532                                 talloc_free(mem_ctx);
533                                 return LDB_ERR_OPERATIONS_ERROR;
534                         }
535                         ret = ldb_msg_add_string(msg, "objectClass", value);
536                         if (ret != LDB_SUCCESS) {
537                                 ldb_set_errstring(ldb,
538                                                   "objectclass: could not re-add sorted "
539                                                   "objectclass to modify msg");
540                                 talloc_free(mem_ctx);
541                                 return ret;
542                         }
543                 }
544
545                 /* Retrive the message again so get_last_structural_class works */
546                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
547
548                 /* Make sure its valid to add an object of this type */
549                 objectclass = get_last_structural_class(schema,objectclass_element);
550                 if(objectclass == NULL) {
551                         ldb_asprintf_errstring(ldb,
552                                                 "Failed to find a structural class for %s",
553                                                   ldb_dn_get_linearized(msg->dn));
554                         return LDB_ERR_NAMING_VIOLATION;
555                 }
556
557                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
558                 if (objectclass->rDNAttID
559                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
560                         ldb_asprintf_errstring(ldb,
561                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
562                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
563                         return LDB_ERR_NAMING_VIOLATION;
564                 }
565
566                 if (ac->search_res && ac->search_res->message) {
567                         struct ldb_message_element *oc_el
568                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
569
570                         bool allowed_class = false;
571                         int i, j;
572                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
573                                 const struct dsdb_class *sclass;
574
575                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
576                                 if (!sclass) {
577                                         /* We don't know this class?  what is going on? */
578                                         continue;
579                                 }
580                                 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
581                                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
582                                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
583                                                         allowed_class = true;
584                                                         break;
585                                                 }
586                                         }
587                                 } else {
588                                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
589                                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
590                                                         allowed_class = true;
591                                                         break;
592                                                 }
593                                         }
594                                 }
595                         }
596
597                         if (!allowed_class) {
598                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
599                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
600                                 return LDB_ERR_NAMING_VIOLATION;
601                         }
602                 }
603
604                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
605                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
606                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
607                         return LDB_ERR_UNWILLING_TO_PERFORM;
608                 }
609
610                 if (!ldb_msg_find_element(msg, "objectCategory")) {
611                         struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
612                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
613                                 /* Strip off extended components */
614                                 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
615                                 value = ldb_dn_alloc_linearized(msg, dn);
616                                 talloc_free(dn);
617                         } else {
618                                 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
619                         }
620                         if (value == NULL) {
621                                 ldb_oom(ldb);
622                                 talloc_free(mem_ctx);
623                                 return LDB_ERR_OPERATIONS_ERROR;
624                         }
625                         ldb_msg_add_string(msg, "objectCategory", value);
626                 }
627                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
628                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
629                                                 "TRUE");
630                 }
631
632                 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
633                 el = ldb_msg_find_element(msg, "systemFlags");
634
635                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
636
637                 if (el) {
638                         /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
639                         /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
640                         ldb_msg_remove_element(msg, el);
641                 }
642
643                 /* This flag is only allowed on attributeSchema objects */
644                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
645                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
646                 }
647
648                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
649                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
650                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
651                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
652                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
653                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
654
655                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
656                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
657                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
658                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
659                 }
660
661                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
662
663                 if (el || systemFlags != 0) {
664                         samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
665                 }
666         }
667
668         talloc_free(mem_ctx);
669         ret = ldb_msg_sanity_check(ldb, msg);
670
671
672         if (ret != LDB_SUCCESS) {
673                 return ret;
674         }
675
676         ret = ldb_build_add_req(&add_req, ldb, ac,
677                                 msg,
678                                 ac->req->controls,
679                                 ac, oc_op_callback,
680                                 ac->req);
681         if (ret != LDB_SUCCESS) {
682                 return ret;
683         }
684
685         /* perform the add */
686         return ldb_next_request(ac->module, add_req);
687 }
688
689 static int oc_modify_callback(struct ldb_request *req,
690                                 struct ldb_reply *ares);
691 static int objectclass_do_mod(struct oc_context *ac);
692
693 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
694 {
695         struct ldb_context *ldb = ldb_module_get_ctx(module);
696         struct ldb_message_element *objectclass_element;
697         struct ldb_message *msg;
698         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
699         struct class_list *sorted, *current;
700         struct ldb_request *down_req;
701         struct oc_context *ac;
702         TALLOC_CTX *mem_ctx;
703         char *value;
704         int ret;
705
706         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
707
708         /* do not manipulate our control entries */
709         if (ldb_dn_is_special(req->op.mod.message->dn)) {
710                 return ldb_next_request(module, req);
711         }
712         
713         /* Without schema, there isn't much to do here */
714         if (!schema) {
715                 return ldb_next_request(module, req);
716         }
717
718         /* As with the "real" AD we don't accept empty messages */
719         if (req->op.mod.message->num_elements == 0) {
720                 ldb_set_errstring(ldb, "objectclass: modify message must have "
721                                        "elements/attributes!");
722                 return LDB_ERR_UNWILLING_TO_PERFORM;
723         }
724
725         ac = oc_init_context(module, req);
726         if (ac == NULL) {
727                 ldb_oom(ldb);
728                 return LDB_ERR_OPERATIONS_ERROR;
729         }
730
731         if (!talloc_reference(ac, schema)) {
732                 ldb_oom(ldb);
733                 return LDB_ERR_OPERATIONS_ERROR;
734         }
735
736         /* If no part of this touches the objectClass, then we don't
737          * need to make any changes.  */
738         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
739
740         /* If the only operation is the deletion of the objectClass
741          * then go on with just fixing the attribute case */
742         if (!objectclass_element) {
743                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
744                 if (msg == NULL) {
745                         return LDB_ERR_OPERATIONS_ERROR;
746                 }
747                 
748                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
749                 if (ret != LDB_SUCCESS) {
750                         return ret;
751                 }
752
753                 ret = ldb_build_mod_req(&down_req, ldb, ac,
754                                         msg,
755                                         req->controls,
756                                         ac, oc_op_callback,
757                                         req);
758                 if (ret != LDB_SUCCESS) {
759                         return ret;
760                 }
761
762                 /* go on with the call chain */
763                 return ldb_next_request(module, down_req);
764         }
765
766         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
767         case LDB_FLAG_MOD_DELETE:
768                 if (objectclass_element->num_values == 0) {
769                         return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
770                 }
771                 break;
772
773         case LDB_FLAG_MOD_REPLACE:
774                 mem_ctx = talloc_new(ac);
775                 if (mem_ctx == NULL) {
776                         return LDB_ERR_OPERATIONS_ERROR;
777                 }
778
779                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
780                 if (msg == NULL) {
781                         talloc_free(mem_ctx);
782                         return LDB_ERR_OPERATIONS_ERROR;
783                 }
784
785                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
786                 if (ret != LDB_SUCCESS) {
787                         talloc_free(mem_ctx);
788                         return ret;
789                 }
790
791                 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
792                 if (ret != LDB_SUCCESS) {
793                         talloc_free(mem_ctx);
794                         return ret;
795                 }
796
797                 /* We must completely replace the existing objectClass entry,
798                  * because we need it sorted */
799                 
800                 ldb_msg_remove_attr(msg, "objectClass");
801                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
802                 
803                 if (ret != LDB_SUCCESS) {
804                         talloc_free(mem_ctx);
805                         return ret;
806                 }
807
808                 /* Move from the linked list back into an ldb msg */
809                 for (current = sorted; current; current = current->next) {
810                         /* copy the value as this string is on the schema
811                          * context and we can't rely on it not changing
812                          * before the operation is over */
813                         value = talloc_strdup(msg,
814                                         current->objectclass->lDAPDisplayName);
815                         if (value == NULL) {
816                                 ldb_oom(ldb);
817                                 talloc_free(mem_ctx);
818                                 return LDB_ERR_OPERATIONS_ERROR;
819                         }
820                         ret = ldb_msg_add_string(msg, "objectClass", value);
821                         if (ret != LDB_SUCCESS) {
822                                 ldb_set_errstring(ldb,
823                                         "objectclass: could not re-add sorted "
824                                         "objectclass to modify msg");
825                                 talloc_free(mem_ctx);
826                                 return ret;
827                         }
828                 }
829                 
830                 talloc_free(mem_ctx);
831
832                 ret = ldb_msg_sanity_check(ldb, msg);
833                 if (ret != LDB_SUCCESS) {
834                         return ret;
835                 }
836
837                 ret = ldb_build_mod_req(&down_req, ldb, ac,
838                                         msg,
839                                         req->controls,
840                                         ac, oc_op_callback,
841                                         req);
842                 if (ret != LDB_SUCCESS) {
843                         return ret;
844                 }
845
846                 /* go on with the call chain */
847                 return ldb_next_request(module, down_req);
848         }
849
850         /* This isn't the default branch of the switch, but a 'in any
851          * other case'.  When a delete isn't for all objectClasses for
852          * example
853          */
854
855         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
856         if (msg == NULL) {
857                 ldb_oom(ldb);
858                 return LDB_ERR_OPERATIONS_ERROR;
859         }
860
861         ret = fix_check_attributes(ldb, schema, msg, req->operation);
862         if (ret != LDB_SUCCESS) {
863                 ldb_oom(ldb);
864                 return ret;
865         }
866
867         ret = ldb_build_mod_req(&down_req, ldb, ac,
868                                 msg,
869                                 req->controls,
870                                 ac, oc_modify_callback,
871                                 req);
872         if (ret != LDB_SUCCESS) {
873                 return ret;
874         }
875
876         return ldb_next_request(module, down_req);
877 }
878
879 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
880 {
881         struct ldb_context *ldb;
882         static const char * const attrs[] = { "objectClass", NULL };
883         struct ldb_request *search_req;
884         struct oc_context *ac;
885         int ret;
886
887         ac = talloc_get_type(req->context, struct oc_context);
888         ldb = ldb_module_get_ctx(ac->module);
889
890         if (!ares) {
891                 return ldb_module_done(ac->req, NULL, NULL,
892                                         LDB_ERR_OPERATIONS_ERROR);
893         }
894         if (ares->error != LDB_SUCCESS) {
895                 return ldb_module_done(ac->req, ares->controls,
896                                         ares->response, ares->error);
897         }
898
899         if (ares->type != LDB_REPLY_DONE) {
900                 talloc_free(ares);
901                 return ldb_module_done(ac->req, NULL, NULL,
902                                         LDB_ERR_OPERATIONS_ERROR);
903         }
904
905         talloc_free(ares);
906
907         ret = ldb_build_search_req(&search_req, ldb, ac,
908                                    ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
909                                    "(objectClass=*)",
910                                    attrs, NULL, 
911                                    ac, get_search_callback,
912                                    ac->req);
913         if (ret != LDB_SUCCESS) {
914                 return ldb_module_done(ac->req, NULL, NULL, ret);
915         }
916
917         ac->step_fn = objectclass_do_mod;
918
919         ret = ldb_next_request(ac->module, search_req);
920         if (ret != LDB_SUCCESS) {
921                 return ldb_module_done(ac->req, NULL, NULL, ret);
922         }
923         return LDB_SUCCESS;
924 }
925
926 static int objectclass_do_mod(struct oc_context *ac)
927 {
928         struct ldb_context *ldb;
929         const struct dsdb_schema *schema;
930         struct ldb_request *mod_req;
931         char *value;
932         struct ldb_message_element *objectclass_element;
933         struct ldb_message *msg;
934         TALLOC_CTX *mem_ctx;
935         struct class_list *sorted, *current;
936         int ret;
937
938         ldb = ldb_module_get_ctx(ac->module);
939
940         if (ac->search_res == NULL) {
941                 return LDB_ERR_OPERATIONS_ERROR;
942         }
943         schema = dsdb_get_schema(ldb, ac);
944
945         mem_ctx = talloc_new(ac);
946         if (mem_ctx == NULL) {
947                 return LDB_ERR_OPERATIONS_ERROR;
948         }
949
950         /* use a new message structure */
951         msg = ldb_msg_new(ac);
952         if (msg == NULL) {
953                 ldb_set_errstring(ldb,
954                         "objectclass: could not create new modify msg");
955                 talloc_free(mem_ctx);
956                 return LDB_ERR_OPERATIONS_ERROR;
957         }
958
959         /* This is now the objectClass list from the database */
960         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
961                                                    "objectClass");
962         if (!objectclass_element) {
963                 /* Where did it go?  bail now... */
964                 talloc_free(mem_ctx);
965                 return LDB_ERR_OPERATIONS_ERROR;
966         }
967         
968         /* modify dn */
969         msg->dn = ac->req->op.mod.message->dn;
970
971         ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
972         if (ret != LDB_SUCCESS) {
973                 return ret;
974         }
975
976         /* We must completely replace the existing objectClass entry.
977          * We could do a constrained add/del, but we are meant to be
978          * in a transaction... */
979
980         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
981         if (ret != LDB_SUCCESS) {
982                 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
983                 talloc_free(mem_ctx);
984                 return ret;
985         }
986         
987         /* Move from the linked list back into an ldb msg */
988         for (current = sorted; current; current = current->next) {
989                 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
990                 if (value == NULL) {
991                         ldb_oom(ldb);
992                         return LDB_ERR_OPERATIONS_ERROR;
993                 }
994                 ret = ldb_msg_add_string(msg, "objectClass", value);
995                 if (ret != LDB_SUCCESS) {
996                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
997                         talloc_free(mem_ctx);
998                         return ret;
999                 }
1000         }
1001
1002         ret = ldb_msg_sanity_check(ldb, msg);
1003         if (ret != LDB_SUCCESS) {
1004                 talloc_free(mem_ctx);
1005                 return ret;
1006         }
1007
1008         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1009                                 msg,
1010                                 ac->req->controls,
1011                                 ac, oc_op_callback,
1012                                 ac->req);
1013         if (ret != LDB_SUCCESS) {
1014                 talloc_free(mem_ctx);
1015                 return ret;
1016         }
1017
1018         talloc_free(mem_ctx);
1019         /* perform the modify */
1020         return ldb_next_request(ac->module, mod_req);
1021 }
1022
1023 static int objectclass_do_rename(struct oc_context *ac);
1024
1025 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1026 {
1027         static const char * const attrs[] = { NULL };
1028         struct ldb_context *ldb;
1029         struct ldb_request *search_req;
1030         struct oc_context *ac;
1031         struct ldb_dn *parent_dn;
1032         int ret;
1033
1034         ldb = ldb_module_get_ctx(module);
1035
1036         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1037
1038         if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1039                 return ldb_next_request(module, req);
1040         }
1041
1042         /* Firstly ensure we are not trying to rename it to be a child of itself */
1043         if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
1044             && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1045                 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1046                                        ldb_dn_get_linearized(req->op.rename.olddn));
1047                 return LDB_ERR_UNWILLING_TO_PERFORM;
1048         }
1049
1050         ac = oc_init_context(module, req);
1051         if (ac == NULL) {
1052                 return LDB_ERR_OPERATIONS_ERROR;
1053         }
1054
1055         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1056         if (parent_dn == NULL) {
1057                 ldb_oom(ldb);
1058                 return LDB_ERR_OPERATIONS_ERROR;
1059         }
1060
1061         /*
1062           it makes a search request, looking for the parent DN to fix up the new DN
1063           to a standard one, at objectclass_do_rename()
1064          */
1065         ret = ldb_build_search_req(&search_req, ldb,
1066                                    ac, parent_dn, LDB_SCOPE_BASE,
1067                                    "(objectClass=*)",
1068                                    attrs, NULL,
1069                                    ac, get_search_callback,
1070                                    req);
1071         if (ret != LDB_SUCCESS) {
1072                 return ret;
1073         }
1074
1075         /* we have to add the show deleted control, as otherwise DRS
1076            deletes will be refused as we will think the target parent
1077            does not exist */
1078         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1079
1080         if (ret != LDB_SUCCESS) {
1081                 return ret;
1082         }
1083
1084         ac->step_fn = objectclass_do_rename;
1085
1086         return ldb_next_request(ac->module, search_req);
1087
1088
1089 }
1090
1091 static int objectclass_do_rename(struct oc_context *ac)
1092 {
1093         struct ldb_context *ldb;
1094         struct ldb_request *rename_req;
1095         struct ldb_dn *fixed_dn;
1096         int ret;
1097
1098         ldb = ldb_module_get_ctx(ac->module);
1099
1100         /* Check we have a valid parent */
1101         if (ac->search_res == NULL) {
1102                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!", 
1103                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1104                 return LDB_ERR_UNWILLING_TO_PERFORM;
1105         }
1106         
1107         /* Fix up the DN to be in the standard form,
1108          * taking particular care to match the parent DN */
1109         ret = fix_dn(ac,
1110                      ac->req->op.rename.newdn,
1111                      ac->search_res->message->dn,
1112                      &fixed_dn);
1113         if (ret != LDB_SUCCESS) {
1114                 return ret;
1115         }
1116
1117         /* TODO: Check this is a valid child to this parent,
1118          * by reading the allowedChildClasses and
1119          * allowedChildClasssesEffective attributes */
1120
1121         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1122                                    ac->req->op.rename.olddn, fixed_dn,
1123                                    ac->req->controls,
1124                                    ac, oc_op_callback,
1125                                    ac->req);
1126         if (ret != LDB_SUCCESS) {
1127                 return ret;
1128         }
1129
1130         /* perform the rename */
1131         return ldb_next_request(ac->module, rename_req);
1132 }
1133
1134 static int objectclass_init(struct ldb_module *module)
1135 {
1136         struct ldb_context *ldb = ldb_module_get_ctx(module);
1137         int ret;
1138         /* Init everything else */
1139         ret = ldb_next_init(module);
1140         if (ret != LDB_SUCCESS) {
1141                 return ret;
1142         }
1143         
1144         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1145         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1146
1147         return ret;
1148 }
1149
1150 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1151         .name              = "objectclass",
1152         .add           = objectclass_add,
1153         .modify        = objectclass_modify,
1154         .rename        = objectclass_rename,
1155         .init_context  = objectclass_init
1156 };