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