s4:objectclass LDB module - weak the check for the "rIDSet" delete constraint
[kai/samba-autobuild/.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 static int objectclass_do_add(struct oc_context *ac)
436 {
437         struct ldb_context *ldb;
438         struct ldb_request *add_req;
439         struct ldb_message_element *objectclass_element, *el;
440         struct ldb_message *msg;
441         TALLOC_CTX *mem_ctx;
442         struct class_list *sorted, *current;
443         const char *rdn_name = NULL;
444         char *value;
445         const struct dsdb_class *objectclass;
446         struct ldb_dn *objectcategory;
447         int32_t systemFlags = 0;
448         int ret;
449
450         ldb = ldb_module_get_ctx(ac->module);
451
452         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
453
454         /* Check if we have a valid parent - this check is needed since
455          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
456         if (ac->search_res == NULL) {
457                 unsigned int instanceType;
458
459                 /* An add operation on partition DNs without "NC-add" operation
460                  * isn't allowed. */
461                 instanceType = ldb_msg_find_attr_as_uint(ac->req->op.add.message,
462                                                          "instanceType", 0);
463                 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
464                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
465                                                ldb_dn_get_linearized(msg->dn));
466                         return LDB_ERR_NO_SUCH_OBJECT;
467                 }
468
469                 /* Don't keep any error messages - we've to add a partition */
470                 ldb_set_errstring(ldb, NULL);
471         } else {
472                 /* Fix up the DN to be in the standard form, taking
473                  * particular care to match the parent DN */
474                 ret = fix_dn(ldb, msg,
475                              ac->req->op.add.message->dn,
476                              ac->search_res->message->dn,
477                              &msg->dn);
478                 if (ret != LDB_SUCCESS) {
479                         ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
480                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
481                         return ret;
482                 }
483         }
484
485         mem_ctx = talloc_new(ac);
486         if (mem_ctx == NULL) {
487                 return ldb_oom(ldb);
488         }
489
490         if (ac->schema != NULL) {
491                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
492                 if (!objectclass_element) {
493                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
494                                                ldb_dn_get_linearized(msg->dn));
495                         talloc_free(mem_ctx);
496                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
497                 }
498
499                 /* Here we do now get the "objectClass" list from the
500                  * database. */
501                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
502                                        objectclass_element, &sorted);
503                 if (ret != LDB_SUCCESS) {
504                         talloc_free(mem_ctx);
505                         return ret;
506                 }
507                 
508                 ldb_msg_remove_element(msg, objectclass_element);
509
510                 /* Well, now we shouldn't find any additional "objectClass"
511                  * message element (required by the AD specification). */
512                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
513                 if (objectclass_element != NULL) {
514                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
515                                                ldb_dn_get_linearized(msg->dn));
516                         talloc_free(mem_ctx);
517                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
518                 }
519
520                 /* We must completely replace the existing objectClass entry,
521                  * because we need it sorted. */
522                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
523                 if (ret != LDB_SUCCESS) {
524                         talloc_free(mem_ctx);
525                         return ret;
526                 }
527
528                 /* Move from the linked list back into an ldb msg */
529                 for (current = sorted; current; current = current->next) {
530                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
531                         if (value == NULL) {
532                                 talloc_free(mem_ctx);
533                                 return ldb_oom(ldb);
534                         }
535                         ret = ldb_msg_add_string(msg, "objectClass", value);
536                         if (ret != LDB_SUCCESS) {
537                                 ldb_set_errstring(ldb,
538                                                   "objectclass: could not re-add sorted "
539                                                   "objectclass to modify msg");
540                                 talloc_free(mem_ctx);
541                                 return ret;
542                         }
543                 }
544
545                 talloc_free(mem_ctx);
546
547                 /* Retrive the message again so get_last_structural_class works */
548                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
549
550                 /* Make sure its valid to add an object of this type */
551                 objectclass = get_last_structural_class(ac->schema,
552                                                         objectclass_element);
553                 if(objectclass == NULL) {
554                         ldb_asprintf_errstring(ldb,
555                                                "Failed to find a structural class for %s",
556                                                ldb_dn_get_linearized(msg->dn));
557                         return LDB_ERR_UNWILLING_TO_PERFORM;
558                 }
559
560                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
561                 if (objectclass->rDNAttID
562                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
563                         ldb_asprintf_errstring(ldb,
564                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
565                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
566                         return LDB_ERR_NAMING_VIOLATION;
567                 }
568
569                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
570                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
571                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
572                         return LDB_ERR_UNWILLING_TO_PERFORM;
573                 }
574
575                 if (((strcmp(objectclass->lDAPDisplayName, "secret") == 0) ||
576                      (strcmp(objectclass->lDAPDisplayName, "trustedDomain") == 0)) &&
577                     !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
578                         ldb_asprintf_errstring(ldb, "objectClass %s is LSA-specific, rejecting creation of %s",
579                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
580                         return LDB_ERR_UNWILLING_TO_PERFORM;
581                 }
582
583                 if (ac->search_res && ac->search_res->message) {
584                         struct ldb_message_element *oc_el
585                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
586
587                         bool allowed_class = false;
588                         unsigned int i, j;
589                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
590                                 const struct dsdb_class *sclass;
591
592                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
593                                                                                &oc_el->values[i]);
594                                 if (!sclass) {
595                                         /* We don't know this class?  what is going on? */
596                                         continue;
597                                 }
598                                 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
599                                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
600                                                 allowed_class = true;
601                                                 break;
602                                         }
603                                 }
604                         }
605
606                         if (!allowed_class) {
607                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
608                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
609                                 return LDB_ERR_NAMING_VIOLATION;
610                         }
611                 }
612
613                 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
614                                                          "objectCategory");
615                 if (objectcategory == NULL) {
616                         struct dsdb_extended_dn_store_format *dn_format =
617                                         talloc_get_type(ldb_module_get_private(ac->module),
618                                                         struct dsdb_extended_dn_store_format);
619                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
620                                 /* Strip off extended components */
621                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
622                                                                objectclass->defaultObjectCategory);
623                                 value = ldb_dn_alloc_linearized(msg, dn);
624                                 talloc_free(dn);
625                         } else {
626                                 value = talloc_strdup(msg,
627                                                       objectclass->defaultObjectCategory);
628                         }
629                         if (value == NULL) {
630                                 return ldb_oom(ldb);
631                         }
632
633                         ret = ldb_msg_add_string(msg, "objectCategory", value);
634                         if (ret != LDB_SUCCESS) {
635                                 return ret;
636                         }
637                 } else {
638                         const struct dsdb_class *ocClass =
639                                         dsdb_class_by_cn_ldb_val(ac->schema,
640                                                                  ldb_dn_get_rdn_val(objectcategory));
641                         if (ocClass != NULL) {
642                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
643                                                                ocClass->defaultObjectCategory);
644                                 if (ldb_dn_compare(objectcategory, dn) != 0) {
645                                         ocClass = NULL;
646                                 }
647                         }
648                         talloc_free(objectcategory);
649                         if (ocClass == NULL) {
650                                 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
651                                                        ldb_dn_get_linearized(msg->dn));
652                                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
653                         }
654                 }
655
656                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
657                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
658                                                 "TRUE");
659                 }
660
661                 /* There are very special rules for systemFlags, see MS-ADTS
662                  * MS-ADTS 3.1.1.5.2.4 */
663
664                 el = ldb_msg_find_element(msg, "systemFlags");
665                 if ((el != NULL) && (el->num_values > 1)) {
666                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'systemFlags' attribute multivalued!",
667                                                ldb_dn_get_linearized(msg->dn));
668                         return LDB_ERR_CONSTRAINT_VIOLATION;
669                 }
670
671                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
672
673                 ldb_msg_remove_attr(msg, "systemFlags");
674
675                 /* Only these flags may be set by a client, but we can't tell
676                  * between a client and our provision at this point
677                  * systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE);
678                  */
679
680                 /* This flag is only allowed on attributeSchema objects */
681                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
682                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
683                 }
684
685                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
686                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
687                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
688                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
689                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
690                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
691
692                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
693                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
694                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
695                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
696                 }
697
698                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
699
700                 if (el || systemFlags != 0) {
701                         ret = samdb_msg_add_int(ldb, msg, msg, "systemFlags",
702                                                 systemFlags);
703                         if (ret != LDB_SUCCESS) {
704                                 return ret;
705                         }
706                 }
707         }
708
709         ret = ldb_msg_sanity_check(ldb, msg);
710         if (ret != LDB_SUCCESS) {
711                 return ret;
712         }
713
714         ret = ldb_build_add_req(&add_req, ldb, ac,
715                                 msg,
716                                 ac->req->controls,
717                                 ac, oc_op_callback,
718                                 ac->req);
719         if (ret != LDB_SUCCESS) {
720                 return ret;
721         }
722
723         /* perform the add */
724         return ldb_next_request(ac->module, add_req);
725 }
726
727 static int oc_modify_callback(struct ldb_request *req,
728                                 struct ldb_reply *ares);
729 static int objectclass_do_mod(struct oc_context *ac);
730
731 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
732 {
733         struct ldb_context *ldb = ldb_module_get_ctx(module);
734         struct ldb_message_element *objectclass_element;
735         struct ldb_message *msg;
736         struct ldb_request *down_req;
737         struct oc_context *ac;
738         bool oc_changes = false;
739         int ret;
740
741         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
742
743         /* do not manipulate our control entries */
744         if (ldb_dn_is_special(req->op.mod.message->dn)) {
745                 return ldb_next_request(module, req);
746         }
747
748         /* As with the "real" AD we don't accept empty messages */
749         if (req->op.mod.message->num_elements == 0) {
750                 ldb_set_errstring(ldb, "objectclass: modify message must have "
751                                        "elements/attributes!");
752                 return LDB_ERR_UNWILLING_TO_PERFORM;
753         }
754
755         ac = oc_init_context(module, req);
756         if (ac == NULL) {
757                 return ldb_operr(ldb);
758         }
759
760         /* Without schema, there isn't much to do here */
761         if (ac->schema == NULL) {
762                 talloc_free(ac);
763                 return ldb_next_request(module, req);
764         }
765
766         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
767         if (msg == NULL) {
768                 return ldb_operr(ldb);
769         }
770
771         /* For now change everything except the objectclasses */
772
773         objectclass_element = ldb_msg_find_element(msg, "objectClass");
774         if (objectclass_element != NULL) {
775                 ldb_msg_remove_attr(msg, "objectClass");
776                 oc_changes = true;
777         }
778
779         ret = ldb_build_mod_req(&down_req, ldb, ac,
780                                 msg,
781                                 req->controls, ac,
782                                 oc_changes ? oc_modify_callback : oc_op_callback,
783                                 req);
784         if (ret != LDB_SUCCESS) {
785                 return ret;
786         }
787
788         return ldb_next_request(module, down_req);
789 }
790
791 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
792 {
793         static const char * const attrs[] = { "objectClass", NULL };
794         struct ldb_context *ldb;
795         struct ldb_request *search_req;
796         struct oc_context *ac;
797         int ret;
798
799         ac = talloc_get_type(req->context, struct oc_context);
800         ldb = ldb_module_get_ctx(ac->module);
801
802         if (!ares) {
803                 return ldb_module_done(ac->req, NULL, NULL,
804                                         LDB_ERR_OPERATIONS_ERROR);
805         }
806
807         if (ares->type == LDB_REPLY_REFERRAL) {
808                 return ldb_module_send_referral(ac->req, ares->referral);
809         }
810
811         if (ares->error != LDB_SUCCESS) {
812                 return ldb_module_done(ac->req, ares->controls,
813                                         ares->response, ares->error);
814         }
815
816         if (ares->type != LDB_REPLY_DONE) {
817                 talloc_free(ares);
818                 return ldb_module_done(ac->req, NULL, NULL,
819                                         LDB_ERR_OPERATIONS_ERROR);
820         }
821
822         talloc_free(ares);
823
824         /* this looks up the real existing object for fetching some important
825          * informations (objectclasses) */
826         ret = ldb_build_search_req(&search_req, ldb,
827                                    ac, ac->req->op.mod.message->dn,
828                                    LDB_SCOPE_BASE,
829                                    "(objectClass=*)",
830                                    attrs, NULL, 
831                                    ac, get_search_callback,
832                                    ac->req);
833         if (ret != LDB_SUCCESS) {
834                 return ldb_module_done(ac->req, NULL, NULL, ret);
835         }
836
837         ac->step_fn = objectclass_do_mod;
838
839         ret = ldb_next_request(ac->module, search_req);
840         if (ret != LDB_SUCCESS) {
841                 return ldb_module_done(ac->req, NULL, NULL, ret);
842         }
843
844         return LDB_SUCCESS;
845 }
846
847 static int objectclass_do_mod(struct oc_context *ac)
848 {
849         struct ldb_context *ldb;
850         struct ldb_request *mod_req;
851         char *value;
852         struct ldb_message_element *oc_el_entry, *oc_el_change;
853         struct ldb_val *vals;
854         struct ldb_message *msg;
855         TALLOC_CTX *mem_ctx;
856         struct class_list *sorted, *current;
857         const struct dsdb_class *objectclass;
858         unsigned int i, j;
859         bool found, replace = false;
860         int ret;
861
862         ldb = ldb_module_get_ctx(ac->module);
863
864         /* we should always have a valid entry when we enter here */
865         if (ac->search_res == NULL) {
866                 return ldb_operr(ldb);
867         }
868
869         oc_el_entry = ldb_msg_find_element(ac->search_res->message,
870                                            "objectClass");
871         if (oc_el_entry == NULL) {
872                 /* existing entry without a valid object class? */
873                 return ldb_operr(ldb);
874         }
875
876         oc_el_change = ldb_msg_find_element(ac->req->op.mod.message,
877                                             "objectClass");
878         if (oc_el_change == NULL) {
879                 /* we should have an objectclass change operation */
880                 return ldb_operr(ldb);
881         }
882
883         /* use a new message structure */
884         msg = ldb_msg_new(ac);
885         if (msg == NULL) {
886                 return ldb_oom(ldb);
887         }
888
889         msg->dn = ac->req->op.mod.message->dn;
890
891         mem_ctx = talloc_new(ac);
892         if (mem_ctx == NULL) {
893                 return ldb_oom(ldb);
894         }
895
896         switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
897         case LDB_FLAG_MOD_ADD:
898                 /* Merge the two message elements */
899                 for (i = 0; i < oc_el_change->num_values; i++) {
900                         for (j = 0; j < oc_el_entry->num_values; j++) {
901                                 if (strcasecmp((char *)oc_el_change->values[i].data,
902                                                (char *)oc_el_entry->values[j].data) == 0) {
903                                         /* we cannot add an already existing object class */
904                                         talloc_free(mem_ctx);
905                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
906                                 }
907                         }
908                         /* append the new object class value - code was copied
909                          * from "ldb_msg_add_value" */
910                         vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
911                                               struct ldb_val,
912                                               oc_el_entry->num_values + 1);
913                         if (vals == NULL) {
914                                 talloc_free(mem_ctx);
915                                 return ldb_oom(ldb);
916                         }
917                         oc_el_entry->values = vals;
918                         oc_el_entry->values[oc_el_entry->num_values] =
919                                 oc_el_change->values[i];
920                         ++(oc_el_entry->num_values);
921                 }
922
923                 objectclass = get_last_structural_class(ac->schema,
924                                                         oc_el_change);
925                 if (objectclass != NULL) {
926                         /* we cannot add a new structural object class */
927                         talloc_free(mem_ctx);
928                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
929                 }
930
931                 /* Now do the sorting */
932                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
933                                        oc_el_entry, &sorted);
934                 if (ret != LDB_SUCCESS) {
935                         talloc_free(mem_ctx);
936                         return ret;
937                 }
938
939                 break;
940
941         case LDB_FLAG_MOD_REPLACE:
942                 /* Do the sorting for the change message element */
943                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
944                                        oc_el_change, &sorted);
945                 if (ret != LDB_SUCCESS) {
946                         talloc_free(mem_ctx);
947                         return ret;
948                 }
949
950                 /* this is a replace */
951                 replace = true;
952
953                 break;
954
955         case LDB_FLAG_MOD_DELETE:
956                 /* get the actual top-most structural objectclass */
957                 objectclass = get_last_structural_class(ac->schema,
958                                                         oc_el_entry);
959                 if (objectclass == NULL) {
960                         talloc_free(mem_ctx);
961                         return ldb_operr(ldb);
962                 }
963
964                 /* Merge the two message elements */
965                 for (i = 0; i < oc_el_change->num_values; i++) {
966                         found = false;
967                         for (j = 0; j < oc_el_entry->num_values; j++) {
968                                 if (strcasecmp((char *)oc_el_change->values[i].data,
969                                                (char *)oc_el_entry->values[j].data) == 0) {
970                                         found = true;
971                                         /* delete the object class value -
972                                          * code was copied from
973                                          * "ldb_msg_remove_element" */
974                                         if (j != oc_el_entry->num_values - 1) {
975                                                 memmove(&oc_el_entry->values[j],
976                                                         &oc_el_entry->values[j+1],
977                                                         ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
978                                         }
979                                         --(oc_el_entry->num_values);
980                                         break;
981                                 }
982                         }
983                         if (!found) {
984                                 /* we cannot delete a not existing object class */
985                                 talloc_free(mem_ctx);
986                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
987                         }
988                 }
989
990                 /* Make sure that the top-most structural objectclass wasn't
991                  * deleted */
992                 found = false;
993                 for (i = 0; i < oc_el_entry->num_values; i++) {
994                         if (strcasecmp(objectclass->lDAPDisplayName,
995                             (char *)oc_el_entry->values[i].data) == 0) {
996                                 found = true; break;
997                         }
998                 }
999                 if (!found) {
1000                         talloc_free(mem_ctx);
1001                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1002                 }
1003
1004
1005                 /* Now do the sorting */
1006                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
1007                                        oc_el_entry, &sorted);
1008                 if (ret != LDB_SUCCESS) {
1009                         talloc_free(mem_ctx);
1010                         return ret;
1011                 }
1012
1013                 break;
1014         }
1015
1016         ret = ldb_msg_add_empty(msg, "objectClass",
1017                                 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1018         if (ret != LDB_SUCCESS) {
1019                 ldb_oom(ldb);
1020                 talloc_free(mem_ctx);
1021                 return ret;
1022         }
1023
1024         /* Move from the linked list back into an ldb msg */
1025         for (current = sorted; current; current = current->next) {
1026                 value = talloc_strdup(msg,
1027                                       current->objectclass->lDAPDisplayName);
1028                 if (value == NULL) {
1029                         talloc_free(mem_ctx);
1030                         return ldb_oom(ldb);
1031                 }
1032                 ret = ldb_msg_add_string(msg, "objectClass", value);
1033                 if (ret != LDB_SUCCESS) {
1034                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1035                         talloc_free(mem_ctx);
1036                         return ret;
1037                 }
1038         }
1039
1040         talloc_free(mem_ctx);
1041
1042         if (replace) {
1043                 /* Well, on replace we are nearly done: we have to test if
1044                  * the change and entry message element are identically. We
1045                  * can use "ldb_msg_element_compare" since now the specified
1046                  * objectclasses match for sure in case. */
1047                 ret = ldb_msg_element_compare(oc_el_entry, oc_el_change);
1048                 if (ret == 0) {
1049                         ret = ldb_msg_element_compare(oc_el_change,
1050                                                       oc_el_entry);
1051                 }
1052                 if (ret == 0) {
1053                         /* they are the same so we are done in this case */
1054                         return ldb_module_done(ac->req, NULL, NULL,
1055                                                LDB_SUCCESS);
1056                 } else {
1057                         /* they're not exactly the same */
1058                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1059                 }
1060         }
1061
1062         /* in the other cases we have the real change left to do */
1063
1064         ret = ldb_msg_sanity_check(ldb, msg);
1065         if (ret != LDB_SUCCESS) {
1066                 return ret;
1067         }
1068
1069         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1070                                 msg,
1071                                 ac->req->controls,
1072                                 ac, oc_op_callback,
1073                                 ac->req);
1074         if (ret != LDB_SUCCESS) {
1075                 return ret;
1076         }
1077
1078         return ldb_next_request(ac->module, mod_req);
1079 }
1080
1081 static int objectclass_do_rename(struct oc_context *ac);
1082
1083 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1084 {
1085         static const char * const attrs[] = { "objectClass", NULL };
1086         struct ldb_context *ldb;
1087         struct ldb_request *search_req;
1088         struct oc_context *ac;
1089         struct ldb_dn *parent_dn;
1090         int ret;
1091
1092         ldb = ldb_module_get_ctx(module);
1093
1094         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1095
1096         /* do not manipulate our control entries */
1097         if (ldb_dn_is_special(req->op.rename.newdn)) {
1098                 return ldb_next_request(module, req);
1099         }
1100
1101         ac = oc_init_context(module, req);
1102         if (ac == NULL) {
1103                 return ldb_operr(ldb);
1104         }
1105
1106         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1107         if (parent_dn == NULL) {
1108                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1109                                        ldb_dn_get_linearized(req->op.rename.olddn));
1110                 return LDB_ERR_NO_SUCH_OBJECT;
1111         }
1112
1113         /* this looks up the parent object for fetching some important
1114          * informations (objectclasses, DN normalisation...) */
1115         ret = ldb_build_search_req(&search_req, ldb,
1116                                    ac, parent_dn, LDB_SCOPE_BASE,
1117                                    "(objectClass=*)",
1118                                    attrs, NULL,
1119                                    ac, get_search_callback,
1120                                    req);
1121         if (ret != LDB_SUCCESS) {
1122                 return ret;
1123         }
1124
1125         /* we have to add the show deleted control, as otherwise DRS
1126            deletes will be refused as we will think the target parent
1127            does not exist */
1128         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1129
1130         if (ret != LDB_SUCCESS) {
1131                 return ret;
1132         }
1133
1134         ac->step_fn = objectclass_do_rename;
1135
1136         return ldb_next_request(ac->module, search_req);
1137 }
1138
1139 static int objectclass_do_rename2(struct oc_context *ac);
1140
1141 static int objectclass_do_rename(struct oc_context *ac)
1142 {
1143         static const char * const attrs[] = { "objectClass", NULL };
1144         struct ldb_context *ldb;
1145         struct ldb_request *search_req;
1146         int ret;
1147
1148         ldb = ldb_module_get_ctx(ac->module);
1149
1150         /* Check if we have a valid parent - this check is needed since
1151          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1152         if (ac->search_res == NULL) {
1153                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1154                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1155                 return LDB_ERR_OTHER;
1156         }
1157
1158         /* now assign "search_res2" to the parent entry to have "search_res"
1159          * free for another lookup */
1160         ac->search_res2 = ac->search_res;
1161         ac->search_res = NULL;
1162
1163         /* this looks up the real existing object for fetching some important
1164          * informations (objectclasses) */
1165         ret = ldb_build_search_req(&search_req, ldb,
1166                                    ac, ac->req->op.rename.olddn,
1167                                    LDB_SCOPE_BASE,
1168                                    "(objectClass=*)",
1169                                    attrs, NULL,
1170                                    ac, get_search_callback,
1171                                    ac->req);
1172         if (ret != LDB_SUCCESS) {
1173                 return ret;
1174         }
1175
1176         ac->step_fn = objectclass_do_rename2;
1177
1178         return ldb_next_request(ac->module, search_req);
1179 }
1180
1181 static int objectclass_do_rename2(struct oc_context *ac)
1182 {
1183         struct ldb_context *ldb;
1184         struct ldb_request *rename_req;
1185         struct ldb_dn *fixed_dn;
1186         int ret;
1187
1188         ldb = ldb_module_get_ctx(ac->module);
1189
1190         /* Check if we have a valid entry - this check is needed since
1191          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1192         if (ac->search_res == NULL) {
1193                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1194                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1195                 return LDB_ERR_NO_SUCH_OBJECT;
1196         }
1197
1198         if (ac->schema != NULL) {
1199                 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1200                 const struct dsdb_class *objectclass;
1201                 const char *rdn_name;
1202                 bool allowed_class = false;
1203                 unsigned int i, j;
1204
1205                 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1206                                                    "objectClass");
1207                 if (oc_el_entry == NULL) {
1208                         /* existing entry without a valid object class? */
1209                         return ldb_operr(ldb);
1210                 }
1211                 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1212                 if (objectclass == NULL) {
1213                         /* existing entry without a valid object class? */
1214                         return ldb_operr(ldb);
1215                 }
1216
1217                 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1218                 if ((objectclass->rDNAttID != NULL) &&
1219                     (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1220                         ldb_asprintf_errstring(ldb,
1221                                                "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1222                                                rdn_name,
1223                                                objectclass->lDAPDisplayName,
1224                                                objectclass->rDNAttID);
1225                         return LDB_ERR_UNWILLING_TO_PERFORM;
1226                 }
1227
1228                 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1229                                                     "objectClass");
1230                 if (oc_el_parent == NULL) {
1231                         /* existing entry without a valid object class? */
1232                         return ldb_operr(ldb);
1233                 }
1234
1235                 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1236                         const struct dsdb_class *sclass;
1237
1238                         sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1239                                                                        &oc_el_parent->values[i]);
1240                         if (!sclass) {
1241                                 /* We don't know this class?  what is going on? */
1242                                 continue;
1243                         }
1244                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1245                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1246                                         allowed_class = true;
1247                                         break;
1248                                 }
1249                         }
1250                 }
1251
1252                 if (!allowed_class) {
1253                         ldb_asprintf_errstring(ldb,
1254                                                "objectclass: structural objectClass %s is not a valid child class for %s",
1255                                                objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1256                         return LDB_ERR_NAMING_VIOLATION;
1257                 }
1258         }
1259
1260         /* Ensure we are not trying to rename it to be a child of itself */
1261         if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1262                                  ac->req->op.rename.newdn) == 0)  &&
1263             (ldb_dn_compare(ac->req->op.rename.olddn,
1264                             ac->req->op.rename.newdn) != 0)) {
1265                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1266                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1267                 return LDB_ERR_UNWILLING_TO_PERFORM;
1268         }
1269
1270         /* Fix up the DN to be in the standard form, taking
1271          * particular care to match the parent DN */
1272         ret = fix_dn(ldb, ac,
1273                      ac->req->op.rename.newdn,
1274                      ac->search_res2->message->dn,
1275                      &fixed_dn);
1276         if (ret != LDB_SUCCESS) {
1277                 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1278                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1279                 return ret;
1280
1281         }
1282
1283         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1284                                    ac->req->op.rename.olddn, fixed_dn,
1285                                    ac->req->controls,
1286                                    ac, oc_op_callback,
1287                                    ac->req);
1288         if (ret != LDB_SUCCESS) {
1289                 return ret;
1290         }
1291
1292         /* perform the rename */
1293         return ldb_next_request(ac->module, rename_req);
1294 }
1295
1296 static int objectclass_do_delete(struct oc_context *ac);
1297
1298 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1299 {
1300         static const char * const attrs[] = { "nCName", "objectClass",
1301                                               "systemFlags", NULL };
1302         struct ldb_context *ldb;
1303         struct ldb_request *search_req;
1304         struct oc_context *ac;
1305         int ret;
1306
1307         ldb = ldb_module_get_ctx(module);
1308
1309         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1310
1311         /* do not manipulate our control entries */
1312         if (ldb_dn_is_special(req->op.del.dn)) {
1313                 return ldb_next_request(module, req);
1314         }
1315
1316         /* Bypass the constraint checks when we do have the "RELAX" control
1317          * set. */
1318         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1319                 return ldb_next_request(module, req);
1320         }
1321
1322         ac = oc_init_context(module, req);
1323         if (ac == NULL) {
1324                 return ldb_operr(ldb);
1325         }
1326
1327         /* this looks up the entry object for fetching some important
1328          * informations (object classes, system flags...) */
1329         ret = ldb_build_search_req(&search_req, ldb,
1330                                    ac, req->op.del.dn, LDB_SCOPE_BASE,
1331                                    "(objectClass=*)",
1332                                    attrs, NULL,
1333                                    ac, get_search_callback,
1334                                    req);
1335         if (ret != LDB_SUCCESS) {
1336                 return ret;
1337         }
1338
1339         ac->step_fn = objectclass_do_delete;
1340
1341         return ldb_next_request(ac->module, search_req);
1342 }
1343
1344 static int objectclass_do_delete(struct oc_context *ac)
1345 {
1346         struct ldb_context *ldb;
1347         struct ldb_dn *dn;
1348         int32_t systemFlags;
1349         int ret;
1350
1351         ldb = ldb_module_get_ctx(ac->module);
1352
1353         /* Check if we have a valid entry - this check is needed since
1354          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1355         if (ac->search_res == NULL) {
1356                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1357                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1358                 return LDB_ERR_NO_SUCH_OBJECT;
1359         }
1360
1361         /* DC's ntDSDSA object */
1362         if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1363                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1364                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1365                 return LDB_ERR_UNWILLING_TO_PERFORM;
1366         }
1367
1368         /* DC's rIDSet object */
1369         /* Perform this check only when it does exist - this is needed in order
1370          * to don't let existing provisions break. */
1371         ret = samdb_rid_set_dn(ldb, ac, &dn);
1372         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1373                 return ret;
1374         }
1375         if (ret == LDB_SUCCESS) {
1376                 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1377                         talloc_free(dn);
1378                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1379                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1380                         return LDB_ERR_UNWILLING_TO_PERFORM;
1381                 }
1382                 talloc_free(dn);
1383         }
1384
1385         /* crossRef objects regarding config, schema and default domain NCs */
1386         if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1387                                  "crossRef") != NULL) {
1388                 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1389                                              "nCName");
1390                 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1391                     (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0) ||
1392                     (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0)) {
1393                         talloc_free(dn);
1394
1395                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the three main partitions!",
1396                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1397                         return LDB_ERR_UNWILLING_TO_PERFORM;
1398                 }
1399                 talloc_free(dn);
1400         }
1401
1402         /* systemFlags */
1403
1404         systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1405                                                "systemFlags", 0);
1406         if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1407                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1408                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1409                 return LDB_ERR_UNWILLING_TO_PERFORM;
1410         }
1411
1412         return ldb_next_request(ac->module, ac->req);
1413 }
1414
1415 static int objectclass_init(struct ldb_module *module)
1416 {
1417         struct ldb_context *ldb = ldb_module_get_ctx(module);
1418         int ret;
1419
1420         /* Init everything else */
1421         ret = ldb_next_init(module);
1422         if (ret != LDB_SUCCESS) {
1423                 return ret;
1424         }
1425         
1426         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1427         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1428
1429         return ret;
1430 }
1431
1432 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1433         .name           = "objectclass",
1434         .add            = objectclass_add,
1435         .modify         = objectclass_modify,
1436         .rename         = objectclass_rename,
1437         .del            = objectclass_delete,
1438         .init_context   = objectclass_init
1439 };