s4-dsdb: support LDB_CONTROL_RODC_DCPROMO_OID for nTDSDSA add
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2006-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6    Copyright (C) Matthias Dieter Wallnöfer 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  *  Name: ldb
24  *
25  *  Component: objectClass sorting and constraint checking module
26  *
27  *  Description: 
28  *  - sort the objectClass attribute into the class
29  *    hierarchy and perform constraint checks (correct RDN name,
30  *    valid parent),
31  *  - fix DNs into 'standard' case
32  *  - Add objectCategory and some other attribute defaults
33  *
34  *  Author: Andrew Bartlett
35  */
36
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "util/dlinklist.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "librpc/ndr/libndr.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "libcli/security/security.h"
45 #include "auth/auth.h"
46 #include "param/param.h"
47 #include "../libds/common/flags.h"
48 #include "util.h"
49
50 struct oc_context {
51
52         struct ldb_module *module;
53         struct ldb_request *req;
54         const struct dsdb_schema *schema;
55
56         struct ldb_reply *search_res;
57         struct ldb_reply *search_res2;
58
59         int (*step_fn)(struct oc_context *);
60 };
61
62 struct class_list {
63         struct class_list *prev, *next;
64         const struct dsdb_class *objectclass;
65 };
66
67 static struct oc_context *oc_init_context(struct ldb_module *module,
68                                           struct ldb_request *req)
69 {
70         struct ldb_context *ldb;
71         struct oc_context *ac;
72
73         ldb = ldb_module_get_ctx(module);
74
75         ac = talloc_zero(req, struct oc_context);
76         if (ac == NULL) {
77                 ldb_oom(ldb);
78                 return NULL;
79         }
80
81         ac->module = module;
82         ac->req = req;
83         ac->schema = dsdb_get_schema(ldb, ac);
84
85         return ac;
86 }
87
88 static int objectclass_do_add(struct oc_context *ac);
89
90 /* Sort objectClasses into correct order, and validate that all
91  * objectClasses specified actually exist in the schema
92  */
93
94 static int objectclass_sort(struct ldb_module *module,
95                             const struct dsdb_schema *schema,
96                             TALLOC_CTX *mem_ctx,
97                             struct ldb_message_element *objectclass_element,
98                             struct class_list **sorted_out) 
99 {
100         struct ldb_context *ldb;
101         unsigned int i, lowest;
102         struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
103
104         ldb = ldb_module_get_ctx(module);
105
106         /* DESIGN:
107          *
108          * We work on 4 different 'bins' (implemented here as linked lists):
109          *
110          * * sorted:       the eventual list, in the order we wish to push
111          *                 into the database.  This is the only ordered list.
112          *
113          * * parent_class: The current parent class 'bin' we are
114          *                 trying to find subclasses for
115          *
116          * * subclass:     The subclasses we have found so far
117          *
118          * * unsorted:     The remaining objectClasses
119          *
120          * The process is a matter of filtering objectClasses up from
121          * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
122          * 
123          * We start with 'top' (found and promoted to parent_class
124          * initially).  Then we find (in unsorted) all the direct
125          * subclasses of 'top'.  parent_classes is concatenated onto
126          * the end of 'sorted', and subclass becomes the list in
127          * parent_class.
128          *
129          * We then repeat, until we find no more subclasses.  Any left
130          * over classes are added to the end.
131          *
132          */
133
134         /* Firstly, dump all the objectClass elements into the
135          * unsorted bin, except for 'top', which is special */
136         for (i=0; i < objectclass_element->num_values; i++) {
137                 current = talloc(mem_ctx, struct class_list);
138                 if (!current) {
139                         return ldb_oom(ldb);
140                 }
141                 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
142                 if (!current->objectclass) {
143                         ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema", 
144                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
145                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
146                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
147                 } else if (current->objectclass->isDefunct) {
148                         ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects", 
149                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
150                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
151                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
152                 }
153
154                 /* Don't add top to list, we will do that later */
155                 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
156                         DLIST_ADD_END(unsorted, current, struct class_list *);
157                 }
158         }
159
160         /* Add top here, to prevent duplicates */
161         current = talloc(mem_ctx, struct class_list);
162         current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
163         DLIST_ADD_END(sorted, current, struct class_list *);
164
165
166         /* For each object:  find parent chain */
167         for (current = unsorted; schema && current; current = current->next) {
168                 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
169                         if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
170                                 break;
171                         }
172                 }
173                 /* If we didn't get to the end of the list, we need to add this parent */
174                 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
175                         continue;
176                 }
177
178                 new_parent = talloc(mem_ctx, struct class_list);
179                 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
180                 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
181         }
182
183         do
184         {
185                 lowest = UINT_MAX;
186                 current_lowest = NULL;
187                 for (current = unsorted; schema && current; current = current->next) {
188                         if(current->objectclass->subClass_order < lowest) {
189                                 current_lowest = current;
190                                 lowest = current->objectclass->subClass_order;
191                         }
192                 }
193
194                 if(current_lowest != NULL) {
195                         DLIST_REMOVE(unsorted,current_lowest);
196                         DLIST_ADD_END(sorted,current_lowest, struct class_list *);
197                 }
198         } while(unsorted);
199
200
201         if (!unsorted) {
202                 *sorted_out = sorted;
203                 return LDB_SUCCESS;
204         }
205
206         if (!schema) {
207                 /* If we don't have schema yet, then just merge the lists again */
208                 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
209                 *sorted_out = sorted;
210                 return LDB_SUCCESS;
211         }
212
213         /* This shouldn't happen, and would break MMC, perhaps there
214          * was no 'top', a conflict in the objectClasses or some other
215          * schema error?
216          */
217         ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
218         return LDB_ERR_OBJECT_CLASS_VIOLATION;
219 }
220
221 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
222 {
223         struct ldb_context *ldb;
224         struct oc_context *ac;
225         int ret;
226
227         ac = talloc_get_type(req->context, struct oc_context);
228         ldb = ldb_module_get_ctx(ac->module);
229
230         if (!ares) {
231                 return ldb_module_done(ac->req, NULL, NULL,
232                                         LDB_ERR_OPERATIONS_ERROR);
233         }
234         if (ares->error != LDB_SUCCESS &&
235             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
236                 return ldb_module_done(ac->req, ares->controls,
237                                         ares->response, ares->error);
238         }
239
240         ldb_reset_err_string(ldb);
241
242         switch (ares->type) {
243         case LDB_REPLY_ENTRY:
244                 if (ac->search_res != NULL) {
245                         ldb_set_errstring(ldb, "Too many results");
246                         talloc_free(ares);
247                         return ldb_module_done(ac->req, NULL, NULL,
248                                                 LDB_ERR_OPERATIONS_ERROR);
249                 }
250
251                 ac->search_res = talloc_steal(ac, ares);
252                 break;
253
254         case LDB_REPLY_REFERRAL:
255                 /* ignore */
256                 talloc_free(ares);
257                 break;
258
259         case LDB_REPLY_DONE:
260                 talloc_free(ares);
261                 ret = ac->step_fn(ac);
262                 if (ret != LDB_SUCCESS) {
263                         return ldb_module_done(ac->req, NULL, NULL, ret);
264                 }
265                 break;
266         }
267
268         return LDB_SUCCESS;
269 }
270
271 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
272 {
273         struct oc_context *ac;
274
275         ac = talloc_get_type(req->context, struct oc_context);
276
277         if (!ares) {
278                 return ldb_module_done(ac->req, NULL, NULL,
279                                         LDB_ERR_OPERATIONS_ERROR);
280         }
281
282         if (ares->type == LDB_REPLY_REFERRAL) {
283                 return ldb_module_send_referral(ac->req, ares->referral);
284         }
285
286         if (ares->error != LDB_SUCCESS) {
287                 return ldb_module_done(ac->req, ares->controls,
288                                         ares->response, ares->error);
289         }
290
291         if (ares->type != LDB_REPLY_DONE) {
292                 talloc_free(ares);
293                 return ldb_module_done(ac->req, NULL, NULL,
294                                         LDB_ERR_OPERATIONS_ERROR);
295         }
296
297         return ldb_module_done(ac->req, ares->controls,
298                                 ares->response, ares->error);
299 }
300
301 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
302
303    This should mean that if the parent is:
304     CN=Users,DC=samba,DC=example,DC=com
305    and a proposed child is
306     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
307
308    The resulting DN should be:
309
310     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
311    
312  */
313 static int fix_dn(struct ldb_context *ldb,
314                   TALLOC_CTX *mem_ctx,
315                   struct ldb_dn *newdn, struct ldb_dn *parent_dn, 
316                   struct ldb_dn **fixed_dn) 
317 {
318         char *upper_rdn_attr;
319         const struct ldb_val *rdn_val;
320
321         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
322         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
323
324         /* We need the attribute name in upper case */
325         upper_rdn_attr = strupper_talloc(*fixed_dn, 
326                                          ldb_dn_get_rdn_name(newdn));
327         if (!upper_rdn_attr) {
328                 return ldb_operr(ldb);
329         }
330
331         /* Create a new child */
332         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
333                 return ldb_operr(ldb);
334         }
335
336
337         rdn_val = ldb_dn_get_rdn_val(newdn);
338
339 #if 0
340         /* the rules for rDN length constraints are more complex than
341         this. Until we understand them we need to leave this
342         constraint out. Otherwise we break replication, as windows
343         does sometimes send us rDNs longer than 64 */
344         if (!rdn_val || rdn_val->length > 64) {
345                 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
346         }
347 #endif
348
349
350         /* And replace it with CN=foo (we need the attribute in upper case */
351         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
352 }
353
354
355 static int objectclass_do_add(struct oc_context *ac);
356
357 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
358 {
359         struct ldb_context *ldb;
360         struct ldb_request *search_req;
361         struct oc_context *ac;
362         struct ldb_dn *parent_dn;
363         const struct ldb_val *val;
364         char *value;
365         int ret;
366         static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
367
368         ldb = ldb_module_get_ctx(module);
369
370         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
371
372         /* do not manipulate our control entries */
373         if (ldb_dn_is_special(req->op.add.message->dn)) {
374                 return ldb_next_request(module, req);
375         }
376
377         /* An add operation on the basedn without "NC-add" operation isn't
378          * allowed. */
379         if (ldb_dn_compare(ldb_get_default_basedn(ldb), req->op.add.message->dn) == 0) {
380                 unsigned int instanceType;
381
382                 instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
383                                                          "instanceType", 0);
384                 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
385                         /* When we are trying to readd the root basedn then
386                          * this is denied, but with an interesting mechanism:
387                          * there is generated a referral with the last
388                          * component value as hostname. */
389                         val = ldb_dn_get_component_val(req->op.add.message->dn,
390                                                        ldb_dn_get_comp_num(req->op.add.message->dn) - 1);
391                         if (val == NULL) {
392                                 return ldb_operr(ldb);
393                         }
394                         value = talloc_asprintf(req, "ldap://%s/%s", val->data,
395                                                 ldb_dn_get_linearized(req->op.add.message->dn));
396                         if (value == NULL) {
397                                 return ldb_oom(ldb);
398                         }
399
400                         return ldb_module_send_referral(req, value);
401                 }
402         }
403
404         ac = oc_init_context(module, req);
405         if (ac == NULL) {
406                 return ldb_operr(ldb);
407         }
408
409         /* If there isn't a parent, just go on to the add processing */
410         if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
411                 return objectclass_do_add(ac);
412         }
413
414         /* get copy of parent DN */
415         parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
416         if (parent_dn == NULL) {
417                 return ldb_oom(ldb);
418         }
419
420         ret = ldb_build_search_req(&search_req, ldb,
421                                    ac, parent_dn, LDB_SCOPE_BASE,
422                                    "(objectClass=*)", parent_attrs,
423                                    NULL,
424                                    ac, get_search_callback,
425                                    req);
426         if (ret != LDB_SUCCESS) {
427                 return ret;
428         }
429
430         ac->step_fn = objectclass_do_add;
431
432         return ldb_next_request(ac->module, search_req);
433 }
434
435
436 /*
437   check if this is a special RODC nTDSDSA add
438  */
439 static bool check_rodc_ntdsdsa_add(struct oc_context *ac,
440                                    const struct dsdb_class *objectclass)
441 {
442         struct ldb_control *rodc_control;
443
444         if (strcasecmp(objectclass->lDAPDisplayName, "nTDSDSA") != 0) {
445                 return false;
446         }
447         rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
448         if (!rodc_control) {
449                 return false;
450         }
451
452         rodc_control->critical = false;
453         return true;
454 }
455
456 static int objectclass_do_add(struct oc_context *ac)
457 {
458         struct ldb_context *ldb;
459         struct ldb_request *add_req;
460         struct ldb_message_element *objectclass_element, *el;
461         struct ldb_message *msg;
462         TALLOC_CTX *mem_ctx;
463         struct class_list *sorted, *current;
464         const char *rdn_name = NULL;
465         char *value;
466         const struct dsdb_class *objectclass;
467         struct ldb_dn *objectcategory;
468         int32_t systemFlags = 0;
469         int ret;
470
471         ldb = ldb_module_get_ctx(ac->module);
472
473         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
474
475         /* Check if we have a valid parent - this check is needed since
476          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
477         if (ac->search_res == NULL) {
478                 unsigned int instanceType;
479
480                 /* An add operation on partition DNs without "NC-add" operation
481                  * isn't allowed. */
482                 instanceType = ldb_msg_find_attr_as_uint(ac->req->op.add.message,
483                                                          "instanceType", 0);
484                 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
485                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
486                                                ldb_dn_get_linearized(msg->dn));
487                         return LDB_ERR_NO_SUCH_OBJECT;
488                 }
489
490                 /* Don't keep any error messages - we've to add a partition */
491                 ldb_set_errstring(ldb, NULL);
492         } else {
493                 /* Fix up the DN to be in the standard form, taking
494                  * particular care to match the parent DN */
495                 ret = fix_dn(ldb, msg,
496                              ac->req->op.add.message->dn,
497                              ac->search_res->message->dn,
498                              &msg->dn);
499                 if (ret != LDB_SUCCESS) {
500                         ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
501                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
502                         return ret;
503                 }
504         }
505
506         mem_ctx = talloc_new(ac);
507         if (mem_ctx == NULL) {
508                 return ldb_oom(ldb);
509         }
510
511         if (ac->schema != NULL) {
512                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
513                 if (!objectclass_element) {
514                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
515                                                ldb_dn_get_linearized(msg->dn));
516                         talloc_free(mem_ctx);
517                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
518                 }
519
520                 /* Here we do now get the "objectClass" list from the
521                  * database. */
522                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
523                                        objectclass_element, &sorted);
524                 if (ret != LDB_SUCCESS) {
525                         talloc_free(mem_ctx);
526                         return ret;
527                 }
528                 
529                 ldb_msg_remove_element(msg, objectclass_element);
530
531                 /* Well, now we shouldn't find any additional "objectClass"
532                  * message element (required by the AD specification). */
533                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
534                 if (objectclass_element != NULL) {
535                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
536                                                ldb_dn_get_linearized(msg->dn));
537                         talloc_free(mem_ctx);
538                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
539                 }
540
541                 /* We must completely replace the existing objectClass entry,
542                  * because we need it sorted. */
543                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
544                 if (ret != LDB_SUCCESS) {
545                         talloc_free(mem_ctx);
546                         return ret;
547                 }
548
549                 /* Move from the linked list back into an ldb msg */
550                 for (current = sorted; current; current = current->next) {
551                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
552                         if (value == NULL) {
553                                 talloc_free(mem_ctx);
554                                 return ldb_oom(ldb);
555                         }
556                         ret = ldb_msg_add_string(msg, "objectClass", value);
557                         if (ret != LDB_SUCCESS) {
558                                 ldb_set_errstring(ldb,
559                                                   "objectclass: could not re-add sorted "
560                                                   "objectclass to modify msg");
561                                 talloc_free(mem_ctx);
562                                 return ret;
563                         }
564                 }
565
566                 talloc_free(mem_ctx);
567
568                 /* Retrive the message again so get_last_structural_class works */
569                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
570
571                 /* Make sure its valid to add an object of this type */
572                 objectclass = get_last_structural_class(ac->schema,
573                                                         objectclass_element);
574                 if(objectclass == NULL) {
575                         ldb_asprintf_errstring(ldb,
576                                                "Failed to find a structural class for %s",
577                                                ldb_dn_get_linearized(msg->dn));
578                         return LDB_ERR_UNWILLING_TO_PERFORM;
579                 }
580
581                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
582                 if (objectclass->rDNAttID
583                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
584                         ldb_asprintf_errstring(ldb,
585                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
586                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
587                         return LDB_ERR_NAMING_VIOLATION;
588                 }
589
590                 if (objectclass->systemOnly &&
591                     !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
592                     !check_rodc_ntdsdsa_add(ac, objectclass)) {
593                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
594                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
595                         return LDB_ERR_UNWILLING_TO_PERFORM;
596                 }
597
598                 if (((strcmp(objectclass->lDAPDisplayName, "secret") == 0) ||
599                      (strcmp(objectclass->lDAPDisplayName, "trustedDomain") == 0)) &&
600                     !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
601                         ldb_asprintf_errstring(ldb, "objectClass %s is LSA-specific, rejecting creation of %s",
602                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
603                         return LDB_ERR_UNWILLING_TO_PERFORM;
604                 }
605
606                 if (ac->search_res && ac->search_res->message) {
607                         struct ldb_message_element *oc_el
608                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
609
610                         bool allowed_class = false;
611                         unsigned int i, j;
612                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
613                                 const struct dsdb_class *sclass;
614
615                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
616                                                                                &oc_el->values[i]);
617                                 if (!sclass) {
618                                         /* We don't know this class?  what is going on? */
619                                         continue;
620                                 }
621                                 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
622                                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
623                                                 allowed_class = true;
624                                                 break;
625                                         }
626                                 }
627                         }
628
629                         if (!allowed_class) {
630                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
631                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
632                                 return LDB_ERR_NAMING_VIOLATION;
633                         }
634                 }
635
636                 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
637                                                          "objectCategory");
638                 if (objectcategory == NULL) {
639                         struct dsdb_extended_dn_store_format *dn_format =
640                                         talloc_get_type(ldb_module_get_private(ac->module),
641                                                         struct dsdb_extended_dn_store_format);
642                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
643                                 /* Strip off extended components */
644                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
645                                                                objectclass->defaultObjectCategory);
646                                 value = ldb_dn_alloc_linearized(msg, dn);
647                                 talloc_free(dn);
648                         } else {
649                                 value = talloc_strdup(msg,
650                                                       objectclass->defaultObjectCategory);
651                         }
652                         if (value == NULL) {
653                                 return ldb_oom(ldb);
654                         }
655
656                         ret = ldb_msg_add_string(msg, "objectCategory", value);
657                         if (ret != LDB_SUCCESS) {
658                                 return ret;
659                         }
660                 } else {
661                         const struct dsdb_class *ocClass =
662                                         dsdb_class_by_cn_ldb_val(ac->schema,
663                                                                  ldb_dn_get_rdn_val(objectcategory));
664                         if (ocClass != NULL) {
665                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
666                                                                ocClass->defaultObjectCategory);
667                                 if (ldb_dn_compare(objectcategory, dn) != 0) {
668                                         ocClass = NULL;
669                                 }
670                         }
671                         talloc_free(objectcategory);
672                         if (ocClass == NULL) {
673                                 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
674                                                        ldb_dn_get_linearized(msg->dn));
675                                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
676                         }
677                 }
678
679                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
680                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
681                                                 "TRUE");
682                 }
683
684                 /* There are very special rules for systemFlags, see MS-ADTS
685                  * MS-ADTS 3.1.1.5.2.4 */
686
687                 el = ldb_msg_find_element(msg, "systemFlags");
688                 if ((el != NULL) && (el->num_values > 1)) {
689                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
690                                                ldb_dn_get_linearized(msg->dn));
691                         return LDB_ERR_CONSTRAINT_VIOLATION;
692                 }
693
694                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
695
696                 ldb_msg_remove_attr(msg, "systemFlags");
697
698                 /* Only these flags may be set by a client, but we can't tell
699                  * between a client and our provision at this point
700                  * systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE);
701                  */
702
703                 /* This flag is only allowed on attributeSchema objects */
704                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
705                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
706                 }
707
708                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
709                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
710                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
711                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
712                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
713                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
714
715                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
716                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
717                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
718                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
719                 }
720
721                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
722
723                 if (el || systemFlags != 0) {
724                         ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
725                                                 systemFlags);
726                         if (ret != LDB_SUCCESS) {
727                                 return ret;
728                         }
729                 }
730         }
731
732         ret = ldb_msg_sanity_check(ldb, msg);
733         if (ret != LDB_SUCCESS) {
734                 return ret;
735         }
736
737         ret = ldb_build_add_req(&add_req, ldb, ac,
738                                 msg,
739                                 ac->req->controls,
740                                 ac, oc_op_callback,
741                                 ac->req);
742         if (ret != LDB_SUCCESS) {
743                 return ret;
744         }
745
746         /* perform the add */
747         return ldb_next_request(ac->module, add_req);
748 }
749
750 static int oc_modify_callback(struct ldb_request *req,
751                                 struct ldb_reply *ares);
752 static int objectclass_do_mod(struct oc_context *ac);
753
754 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
755 {
756         struct ldb_context *ldb = ldb_module_get_ctx(module);
757         struct ldb_message_element *objectclass_element;
758         struct ldb_message *msg;
759         struct ldb_request *down_req;
760         struct oc_context *ac;
761         bool oc_changes = false;
762         int ret;
763
764         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
765
766         /* do not manipulate our control entries */
767         if (ldb_dn_is_special(req->op.mod.message->dn)) {
768                 return ldb_next_request(module, req);
769         }
770
771         /* As with the "real" AD we don't accept empty messages */
772         if (req->op.mod.message->num_elements == 0) {
773                 ldb_set_errstring(ldb, "objectclass: modify message must have "
774                                        "elements/attributes!");
775                 return LDB_ERR_UNWILLING_TO_PERFORM;
776         }
777
778         ac = oc_init_context(module, req);
779         if (ac == NULL) {
780                 return ldb_operr(ldb);
781         }
782
783         /* Without schema, there isn't much to do here */
784         if (ac->schema == NULL) {
785                 talloc_free(ac);
786                 return ldb_next_request(module, req);
787         }
788
789         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
790         if (msg == NULL) {
791                 return ldb_operr(ldb);
792         }
793
794         /* For now change everything except the objectclasses */
795
796         objectclass_element = ldb_msg_find_element(msg, "objectClass");
797         if (objectclass_element != NULL) {
798                 ldb_msg_remove_attr(msg, "objectClass");
799                 oc_changes = true;
800         }
801
802         ret = ldb_build_mod_req(&down_req, ldb, ac,
803                                 msg,
804                                 req->controls, ac,
805                                 oc_changes ? oc_modify_callback : oc_op_callback,
806                                 req);
807         if (ret != LDB_SUCCESS) {
808                 return ret;
809         }
810
811         return ldb_next_request(module, down_req);
812 }
813
814 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
815 {
816         static const char * const attrs[] = { "objectClass", NULL };
817         struct ldb_context *ldb;
818         struct ldb_request *search_req;
819         struct oc_context *ac;
820         int ret;
821
822         ac = talloc_get_type(req->context, struct oc_context);
823         ldb = ldb_module_get_ctx(ac->module);
824
825         if (!ares) {
826                 return ldb_module_done(ac->req, NULL, NULL,
827                                         LDB_ERR_OPERATIONS_ERROR);
828         }
829
830         if (ares->type == LDB_REPLY_REFERRAL) {
831                 return ldb_module_send_referral(ac->req, ares->referral);
832         }
833
834         if (ares->error != LDB_SUCCESS) {
835                 return ldb_module_done(ac->req, ares->controls,
836                                         ares->response, ares->error);
837         }
838
839         if (ares->type != LDB_REPLY_DONE) {
840                 talloc_free(ares);
841                 return ldb_module_done(ac->req, NULL, NULL,
842                                         LDB_ERR_OPERATIONS_ERROR);
843         }
844
845         talloc_free(ares);
846
847         /* this looks up the real existing object for fetching some important
848          * informations (objectclasses) */
849         ret = ldb_build_search_req(&search_req, ldb,
850                                    ac, ac->req->op.mod.message->dn,
851                                    LDB_SCOPE_BASE,
852                                    "(objectClass=*)",
853                                    attrs, NULL, 
854                                    ac, get_search_callback,
855                                    ac->req);
856         if (ret != LDB_SUCCESS) {
857                 return ldb_module_done(ac->req, NULL, NULL, ret);
858         }
859
860         ac->step_fn = objectclass_do_mod;
861
862         ret = ldb_next_request(ac->module, search_req);
863         if (ret != LDB_SUCCESS) {
864                 return ldb_module_done(ac->req, NULL, NULL, ret);
865         }
866
867         return LDB_SUCCESS;
868 }
869
870 static int objectclass_do_mod(struct oc_context *ac)
871 {
872         struct ldb_context *ldb;
873         struct ldb_request *mod_req;
874         char *value;
875         struct ldb_message_element *oc_el_entry, *oc_el_change;
876         struct ldb_val *vals;
877         struct ldb_message *msg;
878         TALLOC_CTX *mem_ctx;
879         struct class_list *sorted, *current;
880         const struct dsdb_class *objectclass;
881         unsigned int i, j;
882         bool found, replace = false;
883         int ret;
884
885         ldb = ldb_module_get_ctx(ac->module);
886
887         /* we should always have a valid entry when we enter here */
888         if (ac->search_res == NULL) {
889                 return ldb_operr(ldb);
890         }
891
892         oc_el_entry = ldb_msg_find_element(ac->search_res->message,
893                                            "objectClass");
894         if (oc_el_entry == NULL) {
895                 /* existing entry without a valid object class? */
896                 return ldb_operr(ldb);
897         }
898
899         oc_el_change = ldb_msg_find_element(ac->req->op.mod.message,
900                                             "objectClass");
901         if (oc_el_change == NULL) {
902                 /* we should have an objectclass change operation */
903                 return ldb_operr(ldb);
904         }
905
906         /* use a new message structure */
907         msg = ldb_msg_new(ac);
908         if (msg == NULL) {
909                 return ldb_oom(ldb);
910         }
911
912         msg->dn = ac->req->op.mod.message->dn;
913
914         mem_ctx = talloc_new(ac);
915         if (mem_ctx == NULL) {
916                 return ldb_oom(ldb);
917         }
918
919         switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
920         case LDB_FLAG_MOD_ADD:
921                 /* Merge the two message elements */
922                 for (i = 0; i < oc_el_change->num_values; i++) {
923                         for (j = 0; j < oc_el_entry->num_values; j++) {
924                                 if (strcasecmp((char *)oc_el_change->values[i].data,
925                                                (char *)oc_el_entry->values[j].data) == 0) {
926                                         /* we cannot add an already existing object class */
927                                         talloc_free(mem_ctx);
928                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
929                                 }
930                         }
931                         /* append the new object class value - code was copied
932                          * from "ldb_msg_add_value" */
933                         vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
934                                               struct ldb_val,
935                                               oc_el_entry->num_values + 1);
936                         if (vals == NULL) {
937                                 talloc_free(mem_ctx);
938                                 return ldb_oom(ldb);
939                         }
940                         oc_el_entry->values = vals;
941                         oc_el_entry->values[oc_el_entry->num_values] =
942                                 oc_el_change->values[i];
943                         ++(oc_el_entry->num_values);
944                 }
945
946                 objectclass = get_last_structural_class(ac->schema,
947                                                         oc_el_change);
948                 if (objectclass != NULL) {
949                         /* we cannot add a new structural object class */
950                         talloc_free(mem_ctx);
951                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
952                 }
953
954                 /* Now do the sorting */
955                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
956                                        oc_el_entry, &sorted);
957                 if (ret != LDB_SUCCESS) {
958                         talloc_free(mem_ctx);
959                         return ret;
960                 }
961
962                 break;
963
964         case LDB_FLAG_MOD_REPLACE:
965                 /* Do the sorting for the change message element */
966                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
967                                        oc_el_change, &sorted);
968                 if (ret != LDB_SUCCESS) {
969                         talloc_free(mem_ctx);
970                         return ret;
971                 }
972
973                 /* this is a replace */
974                 replace = true;
975
976                 break;
977
978         case LDB_FLAG_MOD_DELETE:
979                 /* get the actual top-most structural objectclass */
980                 objectclass = get_last_structural_class(ac->schema,
981                                                         oc_el_entry);
982                 if (objectclass == NULL) {
983                         talloc_free(mem_ctx);
984                         return ldb_operr(ldb);
985                 }
986
987                 /* Merge the two message elements */
988                 for (i = 0; i < oc_el_change->num_values; i++) {
989                         found = false;
990                         for (j = 0; j < oc_el_entry->num_values; j++) {
991                                 if (strcasecmp((char *)oc_el_change->values[i].data,
992                                                (char *)oc_el_entry->values[j].data) == 0) {
993                                         found = true;
994                                         /* delete the object class value -
995                                          * code was copied from
996                                          * "ldb_msg_remove_element" */
997                                         if (j != oc_el_entry->num_values - 1) {
998                                                 memmove(&oc_el_entry->values[j],
999                                                         &oc_el_entry->values[j+1],
1000                                                         ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
1001                                         }
1002                                         --(oc_el_entry->num_values);
1003                                         break;
1004                                 }
1005                         }
1006                         if (!found) {
1007                                 /* we cannot delete a not existing object class */
1008                                 talloc_free(mem_ctx);
1009                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1010                         }
1011                 }
1012
1013                 /* Make sure that the top-most structural objectclass wasn't
1014                  * deleted */
1015                 found = false;
1016                 for (i = 0; i < oc_el_entry->num_values; i++) {
1017                         if (strcasecmp(objectclass->lDAPDisplayName,
1018                             (char *)oc_el_entry->values[i].data) == 0) {
1019                                 found = true; break;
1020                         }
1021                 }
1022                 if (!found) {
1023                         talloc_free(mem_ctx);
1024                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1025                 }
1026
1027
1028                 /* Now do the sorting */
1029                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1030                                        oc_el_entry, &sorted);
1031                 if (ret != LDB_SUCCESS) {
1032                         talloc_free(mem_ctx);
1033                         return ret;
1034                 }
1035
1036                 break;
1037         }
1038
1039         ret = ldb_msg_add_empty(msg, "objectClass",
1040                                 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1041         if (ret != LDB_SUCCESS) {
1042                 ldb_oom(ldb);
1043                 talloc_free(mem_ctx);
1044                 return ret;
1045         }
1046
1047         /* Move from the linked list back into an ldb msg */
1048         for (current = sorted; current; current = current->next) {
1049                 value = talloc_strdup(msg,
1050                                       current->objectclass->lDAPDisplayName);
1051                 if (value == NULL) {
1052                         talloc_free(mem_ctx);
1053                         return ldb_oom(ldb);
1054                 }
1055                 ret = ldb_msg_add_string(msg, "objectClass", value);
1056                 if (ret != LDB_SUCCESS) {
1057                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1058                         talloc_free(mem_ctx);
1059                         return ret;
1060                 }
1061         }
1062
1063         talloc_free(mem_ctx);
1064
1065         if (replace) {
1066                 /* Well, on replace we are nearly done: we have to test if
1067                  * the change and entry message element are identically. We
1068                  * can use "ldb_msg_element_compare" since now the specified
1069                  * objectclasses match for sure in case. */
1070                 ret = ldb_msg_element_compare(oc_el_entry, oc_el_change);
1071                 if (ret == 0) {
1072                         ret = ldb_msg_element_compare(oc_el_change,
1073                                                       oc_el_entry);
1074                 }
1075                 if (ret == 0) {
1076                         /* they are the same so we are done in this case */
1077                         return ldb_module_done(ac->req, NULL, NULL,
1078                                                LDB_SUCCESS);
1079                 } else {
1080                         /* they're not exactly the same */
1081                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1082                 }
1083         }
1084
1085         /* in the other cases we have the real change left to do */
1086
1087         ret = ldb_msg_sanity_check(ldb, msg);
1088         if (ret != LDB_SUCCESS) {
1089                 return ret;
1090         }
1091
1092         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1093                                 msg,
1094                                 ac->req->controls,
1095                                 ac, oc_op_callback,
1096                                 ac->req);
1097         if (ret != LDB_SUCCESS) {
1098                 return ret;
1099         }
1100
1101         return ldb_next_request(ac->module, mod_req);
1102 }
1103
1104 static int objectclass_do_rename(struct oc_context *ac);
1105
1106 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1107 {
1108         static const char * const attrs[] = { "objectClass", NULL };
1109         struct ldb_context *ldb;
1110         struct ldb_request *search_req;
1111         struct oc_context *ac;
1112         struct ldb_dn *parent_dn;
1113         int ret;
1114
1115         ldb = ldb_module_get_ctx(module);
1116
1117         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1118
1119         /* do not manipulate our control entries */
1120         if (ldb_dn_is_special(req->op.rename.newdn)) {
1121                 return ldb_next_request(module, req);
1122         }
1123
1124         ac = oc_init_context(module, req);
1125         if (ac == NULL) {
1126                 return ldb_operr(ldb);
1127         }
1128
1129         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1130         if (parent_dn == NULL) {
1131                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1132                                        ldb_dn_get_linearized(req->op.rename.olddn));
1133                 return LDB_ERR_NO_SUCH_OBJECT;
1134         }
1135
1136         /* this looks up the parent object for fetching some important
1137          * informations (objectclasses, DN normalisation...) */
1138         ret = ldb_build_search_req(&search_req, ldb,
1139                                    ac, parent_dn, LDB_SCOPE_BASE,
1140                                    "(objectClass=*)",
1141                                    attrs, NULL,
1142                                    ac, get_search_callback,
1143                                    req);
1144         if (ret != LDB_SUCCESS) {
1145                 return ret;
1146         }
1147
1148         /* we have to add the show deleted control, as otherwise DRS
1149            deletes will be refused as we will think the target parent
1150            does not exist */
1151         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1152
1153         if (ret != LDB_SUCCESS) {
1154                 return ret;
1155         }
1156
1157         ac->step_fn = objectclass_do_rename;
1158
1159         return ldb_next_request(ac->module, search_req);
1160 }
1161
1162 static int objectclass_do_rename2(struct oc_context *ac);
1163
1164 static int objectclass_do_rename(struct oc_context *ac)
1165 {
1166         static const char * const attrs[] = { "objectClass", NULL };
1167         struct ldb_context *ldb;
1168         struct ldb_request *search_req;
1169         int ret;
1170
1171         ldb = ldb_module_get_ctx(ac->module);
1172
1173         /* Check if we have a valid parent - this check is needed since
1174          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1175         if (ac->search_res == NULL) {
1176                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1177                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1178                 return LDB_ERR_OTHER;
1179         }
1180
1181         /* now assign "search_res2" to the parent entry to have "search_res"
1182          * free for another lookup */
1183         ac->search_res2 = ac->search_res;
1184         ac->search_res = NULL;
1185
1186         /* this looks up the real existing object for fetching some important
1187          * informations (objectclasses) */
1188         ret = ldb_build_search_req(&search_req, ldb,
1189                                    ac, ac->req->op.rename.olddn,
1190                                    LDB_SCOPE_BASE,
1191                                    "(objectClass=*)",
1192                                    attrs, NULL,
1193                                    ac, get_search_callback,
1194                                    ac->req);
1195         if (ret != LDB_SUCCESS) {
1196                 return ret;
1197         }
1198
1199         ac->step_fn = objectclass_do_rename2;
1200
1201         return ldb_next_request(ac->module, search_req);
1202 }
1203
1204 static int objectclass_do_rename2(struct oc_context *ac)
1205 {
1206         struct ldb_context *ldb;
1207         struct ldb_request *rename_req;
1208         struct ldb_dn *fixed_dn;
1209         int ret;
1210
1211         ldb = ldb_module_get_ctx(ac->module);
1212
1213         /* Check if we have a valid entry - this check is needed since
1214          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1215         if (ac->search_res == NULL) {
1216                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1217                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1218                 return LDB_ERR_NO_SUCH_OBJECT;
1219         }
1220
1221         if (ac->schema != NULL) {
1222                 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1223                 const struct dsdb_class *objectclass;
1224                 const char *rdn_name;
1225                 bool allowed_class = false;
1226                 unsigned int i, j;
1227
1228                 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1229                                                    "objectClass");
1230                 if (oc_el_entry == NULL) {
1231                         /* existing entry without a valid object class? */
1232                         return ldb_operr(ldb);
1233                 }
1234                 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1235                 if (objectclass == NULL) {
1236                         /* existing entry without a valid object class? */
1237                         return ldb_operr(ldb);
1238                 }
1239
1240                 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1241                 if ((objectclass->rDNAttID != NULL) &&
1242                     (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1243                         ldb_asprintf_errstring(ldb,
1244                                                "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1245                                                rdn_name,
1246                                                objectclass->lDAPDisplayName,
1247                                                objectclass->rDNAttID);
1248                         return LDB_ERR_UNWILLING_TO_PERFORM;
1249                 }
1250
1251                 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1252                                                     "objectClass");
1253                 if (oc_el_parent == NULL) {
1254                         /* existing entry without a valid object class? */
1255                         return ldb_operr(ldb);
1256                 }
1257
1258                 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1259                         const struct dsdb_class *sclass;
1260
1261                         sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1262                                                                        &oc_el_parent->values[i]);
1263                         if (!sclass) {
1264                                 /* We don't know this class?  what is going on? */
1265                                 continue;
1266                         }
1267                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1268                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1269                                         allowed_class = true;
1270                                         break;
1271                                 }
1272                         }
1273                 }
1274
1275                 if (!allowed_class) {
1276                         ldb_asprintf_errstring(ldb,
1277                                                "objectclass: structural objectClass %s is not a valid child class for %s",
1278                                                objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1279                         return LDB_ERR_NAMING_VIOLATION;
1280                 }
1281         }
1282
1283         /* Ensure we are not trying to rename it to be a child of itself */
1284         if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1285                                  ac->req->op.rename.newdn) == 0)  &&
1286             (ldb_dn_compare(ac->req->op.rename.olddn,
1287                             ac->req->op.rename.newdn) != 0)) {
1288                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1289                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1290                 return LDB_ERR_UNWILLING_TO_PERFORM;
1291         }
1292
1293         /* Fix up the DN to be in the standard form, taking
1294          * particular care to match the parent DN */
1295         ret = fix_dn(ldb, ac,
1296                      ac->req->op.rename.newdn,
1297                      ac->search_res2->message->dn,
1298                      &fixed_dn);
1299         if (ret != LDB_SUCCESS) {
1300                 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1301                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1302                 return ret;
1303
1304         }
1305
1306         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1307                                    ac->req->op.rename.olddn, fixed_dn,
1308                                    ac->req->controls,
1309                                    ac, oc_op_callback,
1310                                    ac->req);
1311         if (ret != LDB_SUCCESS) {
1312                 return ret;
1313         }
1314
1315         /* perform the rename */
1316         return ldb_next_request(ac->module, rename_req);
1317 }
1318
1319 static int objectclass_do_delete(struct oc_context *ac);
1320
1321 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1322 {
1323         static const char * const attrs[] = { "nCName", "objectClass",
1324                                               "systemFlags", NULL };
1325         struct ldb_context *ldb;
1326         struct ldb_request *search_req;
1327         struct oc_context *ac;
1328         int ret;
1329
1330         ldb = ldb_module_get_ctx(module);
1331
1332         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1333
1334         /* do not manipulate our control entries */
1335         if (ldb_dn_is_special(req->op.del.dn)) {
1336                 return ldb_next_request(module, req);
1337         }
1338
1339         /* Bypass the constraint checks when we do have the "RELAX" control
1340          * set. */
1341         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1342                 return ldb_next_request(module, req);
1343         }
1344
1345         ac = oc_init_context(module, req);
1346         if (ac == NULL) {
1347                 return ldb_operr(ldb);
1348         }
1349
1350         /* this looks up the entry object for fetching some important
1351          * informations (object classes, system flags...) */
1352         ret = ldb_build_search_req(&search_req, ldb,
1353                                    ac, req->op.del.dn, LDB_SCOPE_BASE,
1354                                    "(objectClass=*)",
1355                                    attrs, NULL,
1356                                    ac, get_search_callback,
1357                                    req);
1358         if (ret != LDB_SUCCESS) {
1359                 return ret;
1360         }
1361
1362         ac->step_fn = objectclass_do_delete;
1363
1364         return ldb_next_request(ac->module, search_req);
1365 }
1366
1367 static int objectclass_do_delete(struct oc_context *ac)
1368 {
1369         struct ldb_context *ldb;
1370         struct ldb_dn *dn;
1371         int32_t systemFlags;
1372         int ret;
1373
1374         ldb = ldb_module_get_ctx(ac->module);
1375
1376         /* Check if we have a valid entry - this check is needed since
1377          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1378         if (ac->search_res == NULL) {
1379                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1380                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1381                 return LDB_ERR_NO_SUCH_OBJECT;
1382         }
1383
1384         /* DC's ntDSDSA object */
1385         if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1386                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1387                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1388                 return LDB_ERR_UNWILLING_TO_PERFORM;
1389         }
1390
1391         /* DC's rIDSet object */
1392         /* Perform this check only when it does exist - this is needed in order
1393          * to don't let existing provisions break. */
1394         ret = samdb_rid_set_dn(ldb, ac, &dn);
1395         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1396                 return ret;
1397         }
1398         if (ret == LDB_SUCCESS) {
1399                 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1400                         talloc_free(dn);
1401                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1402                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1403                         return LDB_ERR_UNWILLING_TO_PERFORM;
1404                 }
1405                 talloc_free(dn);
1406         }
1407
1408         /* crossRef objects regarding config, schema and default domain NCs */
1409         if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1410                                  "crossRef") != NULL) {
1411                 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1412                                              "nCName");
1413                 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1414                     (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0) ||
1415                     (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0)) {
1416                         talloc_free(dn);
1417
1418                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the three main partitions!",
1419                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1420                         return LDB_ERR_UNWILLING_TO_PERFORM;
1421                 }
1422                 talloc_free(dn);
1423         }
1424
1425         /* systemFlags */
1426
1427         systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1428                                                "systemFlags", 0);
1429         if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1430                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1431                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1432                 return LDB_ERR_UNWILLING_TO_PERFORM;
1433         }
1434
1435         return ldb_next_request(ac->module, ac->req);
1436 }
1437
1438 static int objectclass_init(struct ldb_module *module)
1439 {
1440         struct ldb_context *ldb = ldb_module_get_ctx(module);
1441         int ret;
1442
1443         /* Init everything else */
1444         ret = ldb_next_init(module);
1445         if (ret != LDB_SUCCESS) {
1446                 return ret;
1447         }
1448         
1449         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1450         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1451
1452         return ret;
1453 }
1454
1455 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1456         .name           = "objectclass",
1457         .add            = objectclass_add,
1458         .modify         = objectclass_modify,
1459         .rename         = objectclass_rename,
1460         .del            = objectclass_delete,
1461         .init_context   = objectclass_init
1462 };