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