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