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