3b2fcd6452524c3d599a17d68f68d6cbf9adb28c
[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 *current_structural_objectclass;
817         const struct dsdb_class *objectclass;
818         unsigned int i, j, k;
819         bool found;
820         int ret;
821
822         ldb = ldb_module_get_ctx(ac->module);
823
824         /* we should always have a valid entry when we enter here */
825         if (ac->search_res == NULL) {
826                 return ldb_operr(ldb);
827         }
828
829         oc_el_entry = ldb_msg_find_element(ac->search_res->message,
830                                            "objectClass");
831         if (oc_el_entry == NULL) {
832                 /* existing entry without a valid object class? */
833                 return ldb_operr(ldb);
834         }
835
836         /*
837          * Get the current new top-most structural object class
838          *
839          * We must not allow this to change
840          */
841
842         current_structural_objectclass
843                 = dsdb_get_last_structural_class(ac->schema,
844                                                  oc_el_entry);
845         if (current_structural_objectclass == NULL) {
846                 ldb_asprintf_errstring(ldb,
847                                        "objectclass: cannot find current structural objectclass on %s!",
848                                        ldb_dn_get_linearized(ac->search_res->message->dn));
849                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
850         }
851
852         /* use a new message structure */
853         msg = ldb_msg_new(ac);
854         if (msg == NULL) {
855                 return ldb_module_oom(ac->module);
856         }
857
858         msg->dn = ac->req->op.mod.message->dn;
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                                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
881                                         }
882                                 }
883                                 /* append the new object class value - code was
884                                  * copied from "ldb_msg_add_value" */
885                                 vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
886                                                       struct ldb_val,
887                                                       oc_el_entry->num_values + 1);
888                                 if (vals == NULL) {
889                                         return ldb_module_oom(ac->module);
890                                 }
891                                 oc_el_entry->values = vals;
892                                 oc_el_entry->values[oc_el_entry->num_values] =
893                                                         oc_el_change->values[i];
894                                 ++(oc_el_entry->num_values);
895                         }
896
897                         break;
898
899                 case LDB_FLAG_MOD_REPLACE:
900                         /*
901                          * In this case the new "oc_el_entry" is simply
902                          * "oc_el_change"
903                          */
904                         oc_el_entry = oc_el_change;
905
906                         break;
907
908                 case LDB_FLAG_MOD_DELETE:
909                         /* Merge the two message elements */
910                         for (i = 0; i < oc_el_change->num_values; i++) {
911                                 found = false;
912                                 for (j = 0; j < oc_el_entry->num_values; j++) {
913                                         if (ldb_attr_cmp((char *)oc_el_change->values[i].data,
914                                                          (char *)oc_el_entry->values[j].data) == 0) {
915                                                 found = true;
916                                                 /* delete the object class value
917                                                  * - code was copied from
918                                                  * "ldb_msg_remove_element" */
919                                                 if (j != oc_el_entry->num_values - 1) {
920                                                         memmove(&oc_el_entry->values[j],
921                                                                 &oc_el_entry->values[j+1],
922                                                                 ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
923                                                 }
924                                                 --(oc_el_entry->num_values);
925                                                 break;
926                                         }
927                                 }
928                                 if (!found) {
929                                         /* we cannot delete a not existing
930                                          * object class */
931                                         ldb_asprintf_errstring(ldb,
932                                                                "objectclass: cannot delete this objectclass: '%.*s'!",
933                                                                (int)oc_el_change->values[i].length,
934                                                                (const char *)oc_el_change->values[i].data);
935                                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
936                                 }
937                         }
938
939                         break;
940                 }
941
942                 /* Now do the sorting */
943                 ret = dsdb_sort_objectClass_attr(ldb, ac->schema, oc_el_entry,
944                                                  msg, oc_el_entry);
945                 if (ret != LDB_SUCCESS) {
946                         return ret;
947                 }
948
949                 /*
950                  * Get the new top-most structural object class and check for
951                  * unrelated structural classes
952                  */
953                 objectclass = dsdb_get_last_structural_class(ac->schema,
954                                                              oc_el_entry);
955                 if (objectclass == NULL) {
956                         ldb_set_errstring(ldb,
957                                           "objectclass: cannot delete all structural objectclasses!");
958                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
959                 }
960
961                 /*
962                  * Has (so far, we re-check for each and every
963                  * "objectclass" in the message) the structural
964                  * objectclass changed?
965                  */
966
967                 if (objectclass != current_structural_objectclass) {
968                         const char *dn
969                                 = ldb_dn_get_linearized(ac->search_res->message->dn);
970                         ldb_asprintf_errstring(ldb,
971                                                "objectclass: not permitted "
972                                                "to change the structural "
973                                                "objectClass on %s [%s] => [%s]!",
974                                                dn,
975                                                current_structural_objectclass->lDAPDisplayName,
976                                                objectclass->lDAPDisplayName);
977                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
978                 }
979
980                 /* Check for unrelated objectclasses */
981                 ret = check_unrelated_objectclasses(ac->module, ac->schema,
982                                                     objectclass,
983                                                     oc_el_entry);
984                 if (ret != LDB_SUCCESS) {
985                         return ret;
986                 }
987         }
988
989         /* Now add the new object class attribute to the change message */
990         ret = ldb_msg_add(msg, oc_el_entry, LDB_FLAG_MOD_REPLACE);
991         if (ret != LDB_SUCCESS) {
992                 ldb_module_oom(ac->module);
993                 return ret;
994         }
995
996         /* Now we have the real and definitive change left to do */
997
998         ret = ldb_build_mod_req(&mod_req, ldb, ac,
999                                 msg,
1000                                 ac->req->controls,
1001                                 ac->req, dsdb_next_callback,
1002                                 ac->req);
1003         LDB_REQ_SET_LOCATION(mod_req);
1004         if (ret != LDB_SUCCESS) {
1005                 return ret;
1006         }
1007
1008         return ldb_next_request(ac->module, mod_req);
1009 }
1010
1011 static int objectclass_do_rename(struct oc_context *ac);
1012
1013 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1014 {
1015         static const char * const attrs[] = { "objectClass", NULL };
1016         struct ldb_context *ldb;
1017         struct ldb_request *search_req;
1018         struct oc_context *ac;
1019         struct ldb_dn *parent_dn;
1020         int ret;
1021
1022         ldb = ldb_module_get_ctx(module);
1023
1024         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1025
1026         /* do not manipulate our control entries */
1027         if (ldb_dn_is_special(req->op.rename.olddn)) {
1028                 return ldb_next_request(module, req);
1029         }
1030
1031         /*
1032          * Bypass the constraint checks when we do have the "DBCHECK" control
1033          * set, so we can force objects under the deleted objects container.
1034          */
1035         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK) != NULL) {
1036                 return ldb_next_request(module, req);
1037         }
1038
1039         ac = oc_init_context(module, req);
1040         if (ac == NULL) {
1041                 return ldb_operr(ldb);
1042         }
1043
1044         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1045         if (parent_dn == NULL) {
1046                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1047                                        ldb_dn_get_linearized(req->op.rename.olddn));
1048                 return LDB_ERR_NO_SUCH_OBJECT;
1049         }
1050
1051         /* this looks up the parent object for fetching some important
1052          * information (objectclasses, DN normalisation...) */
1053         ret = ldb_build_search_req(&search_req, ldb,
1054                                    ac, parent_dn, LDB_SCOPE_BASE,
1055                                    "(objectClass=*)",
1056                                    attrs, NULL,
1057                                    ac, get_search_callback,
1058                                    req);
1059         LDB_REQ_SET_LOCATION(search_req);
1060         if (ret != LDB_SUCCESS) {
1061                 return ret;
1062         }
1063
1064         /* we have to add the show recycled control, as otherwise DRS
1065            deletes will be refused as we will think the target parent
1066            does not exist */
1067         ret = dsdb_request_add_controls(search_req,
1068                                         DSDB_FLAG_AS_SYSTEM |
1069                                         DSDB_SEARCH_SHOW_RECYCLED);
1070         if (ret != LDB_SUCCESS) {
1071                 return ret;
1072         }
1073
1074         ac->step_fn = objectclass_do_rename;
1075
1076         return ldb_next_request(ac->module, search_req);
1077 }
1078
1079 static int objectclass_do_rename2(struct oc_context *ac);
1080
1081 static int objectclass_do_rename(struct oc_context *ac)
1082 {
1083         static const char * const attrs[] = { "objectClass", NULL };
1084         struct ldb_context *ldb;
1085         struct ldb_request *search_req;
1086         int ret;
1087
1088         ldb = ldb_module_get_ctx(ac->module);
1089
1090         /* Check if we have a valid parent - this check is needed since
1091          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1092         if (ac->search_res == NULL) {
1093                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1094                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1095                 return LDB_ERR_OTHER;
1096         }
1097
1098         /* now assign "search_res2" to the parent entry to have "search_res"
1099          * free for another lookup */
1100         ac->search_res2 = ac->search_res;
1101         ac->search_res = NULL;
1102
1103         /* this looks up the real existing object for fetching some important
1104          * information (objectclasses) */
1105         ret = ldb_build_search_req(&search_req, ldb,
1106                                    ac, ac->req->op.rename.olddn,
1107                                    LDB_SCOPE_BASE,
1108                                    "(objectClass=*)",
1109                                    attrs, NULL,
1110                                    ac, get_search_callback,
1111                                    ac->req);
1112         LDB_REQ_SET_LOCATION(search_req);
1113         if (ret != LDB_SUCCESS) {
1114                 return ret;
1115         }
1116
1117         ret = dsdb_request_add_controls(search_req,
1118                                         DSDB_FLAG_AS_SYSTEM |
1119                                         DSDB_SEARCH_SHOW_RECYCLED);
1120         if (ret != LDB_SUCCESS) {
1121                 return ret;
1122         }
1123
1124         ac->step_fn = objectclass_do_rename2;
1125
1126         return ldb_next_request(ac->module, search_req);
1127 }
1128
1129 static int objectclass_do_rename2(struct oc_context *ac)
1130 {
1131         struct ldb_context *ldb;
1132         struct ldb_request *rename_req;
1133         struct ldb_dn *fixed_dn;
1134         int ret;
1135
1136         ldb = ldb_module_get_ctx(ac->module);
1137
1138         /* Check if we have a valid entry - this check is needed since
1139          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1140         if (ac->search_res == NULL) {
1141                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1142                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1143                 return LDB_ERR_NO_SUCH_OBJECT;
1144         }
1145
1146         if (ac->schema != NULL) {
1147                 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1148                 const struct dsdb_class *objectclass;
1149                 const char *rdn_name;
1150                 bool allowed_class = false;
1151                 unsigned int i, j;
1152                 bool found;
1153
1154                 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1155                                                    "objectClass");
1156                 if (oc_el_entry == NULL) {
1157                         /* existing entry without a valid object class? */
1158                         return ldb_operr(ldb);
1159                 }
1160                 objectclass = dsdb_get_last_structural_class(ac->schema,
1161                                                              oc_el_entry);
1162                 if (objectclass == NULL) {
1163                         /* existing entry without a valid object class? */
1164                         return ldb_operr(ldb);
1165                 }
1166
1167                 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1168                 if (rdn_name == NULL) {
1169                         return ldb_operr(ldb);
1170                 }
1171                 found = false;
1172                 for (i = 0; (!found) && (i < oc_el_entry->num_values); i++) {
1173                         const struct dsdb_class *tmp_class =
1174                                 dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1175                                                                       &oc_el_entry->values[i]);
1176
1177                         if (tmp_class == NULL) continue;
1178
1179                         if (ldb_attr_cmp(rdn_name, tmp_class->rDNAttID) == 0)
1180                                 found = true;
1181                 }
1182                 if (!found) {
1183                         ldb_asprintf_errstring(ldb,
1184                                                "objectclass: Invalid RDN '%s' for objectclass '%s'!",
1185                                                rdn_name, objectclass->lDAPDisplayName);
1186                         return LDB_ERR_UNWILLING_TO_PERFORM;
1187                 }
1188
1189                 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1190                                                     "objectClass");
1191                 if (oc_el_parent == NULL) {
1192                         /* existing entry without a valid object class? */
1193                         return ldb_operr(ldb);
1194                 }
1195
1196                 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1197                         const struct dsdb_class *sclass;
1198
1199                         sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1200                                                                        &oc_el_parent->values[i]);
1201                         if (!sclass) {
1202                                 /* We don't know this class?  what is going on? */
1203                                 continue;
1204                         }
1205                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1206                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1207                                         allowed_class = true;
1208                                         break;
1209                                 }
1210                         }
1211                 }
1212
1213                 if (!allowed_class) {
1214                         ldb_asprintf_errstring(ldb,
1215                                                "objectclass: structural objectClass %s is not a valid child class for %s",
1216                                                objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1217                         return LDB_ERR_NAMING_VIOLATION;
1218                 }
1219         }
1220
1221         /* Ensure we are not trying to rename it to be a child of itself */
1222         if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1223                                  ac->req->op.rename.newdn) == 0)  &&
1224             (ldb_dn_compare(ac->req->op.rename.olddn,
1225                             ac->req->op.rename.newdn) != 0)) {
1226                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1227                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1228                 return LDB_ERR_UNWILLING_TO_PERFORM;
1229         }
1230
1231         /* Fix up the DN to be in the standard form, taking
1232          * particular care to match the parent DN */
1233         ret = fix_dn(ldb, ac,
1234                      ac->req->op.rename.newdn,
1235                      ac->search_res2->message->dn,
1236                      &fixed_dn);
1237         if (ret != LDB_SUCCESS) {
1238                 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1239                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1240                 return ret;
1241
1242         }
1243
1244         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1245                                    ac->req->op.rename.olddn, fixed_dn,
1246                                    ac->req->controls,
1247                                    ac->req, dsdb_next_callback,
1248                                    ac->req);
1249         LDB_REQ_SET_LOCATION(rename_req);
1250         if (ret != LDB_SUCCESS) {
1251                 return ret;
1252         }
1253
1254         /* perform the rename */
1255         return ldb_next_request(ac->module, rename_req);
1256 }
1257
1258 static int objectclass_do_delete(struct oc_context *ac);
1259
1260 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1261 {
1262         static const char * const attrs[] = { "nCName", "objectClass",
1263                                               "systemFlags",
1264                                               "isDeleted",
1265                                               "isCriticalSystemObject", NULL };
1266         struct ldb_context *ldb;
1267         struct ldb_request *search_req;
1268         struct oc_context *ac;
1269         int ret;
1270
1271         ldb = ldb_module_get_ctx(module);
1272
1273         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1274
1275         /* do not manipulate our control entries */
1276         if (ldb_dn_is_special(req->op.del.dn)) {
1277                 return ldb_next_request(module, req);
1278         }
1279
1280         /* Bypass the constraint checks when we do have the "RELAX" control
1281          * set. */
1282         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1283                 return ldb_next_request(module, req);
1284         }
1285
1286         ac = oc_init_context(module, req);
1287         if (ac == NULL) {
1288                 return ldb_operr(ldb);
1289         }
1290
1291         /* this looks up the entry object for fetching some important
1292          * information (object classes, system flags...) */
1293         ret = ldb_build_search_req(&search_req, ldb,
1294                                    ac, req->op.del.dn, LDB_SCOPE_BASE,
1295                                    "(objectClass=*)",
1296                                    attrs, NULL,
1297                                    ac, get_search_callback,
1298                                    req);
1299         LDB_REQ_SET_LOCATION(search_req);
1300         if (ret != LDB_SUCCESS) {
1301                 return ret;
1302         }
1303
1304         ret = dsdb_request_add_controls(search_req,
1305                                         DSDB_FLAG_AS_SYSTEM |
1306                                         DSDB_SEARCH_SHOW_RECYCLED);
1307         if (ret != LDB_SUCCESS) {
1308                 return ret;
1309         }
1310
1311         ac->step_fn = objectclass_do_delete;
1312
1313         return ldb_next_request(ac->module, search_req);
1314 }
1315
1316 static int objectclass_do_delete(struct oc_context *ac)
1317 {
1318         struct ldb_context *ldb;
1319         struct ldb_dn *dn;
1320         int32_t systemFlags;
1321         bool isCriticalSystemObject;
1322         int ret;
1323
1324         ldb = ldb_module_get_ctx(ac->module);
1325
1326         /* Check if we have a valid entry - this check is needed since
1327          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1328         if (ac->search_res == NULL) {
1329                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1330                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1331                 return LDB_ERR_NO_SUCH_OBJECT;
1332         }
1333
1334         /* DC's ntDSDSA object */
1335         if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb, ac)) == 0) {
1336                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1337                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1338                 return LDB_ERR_UNWILLING_TO_PERFORM;
1339         }
1340
1341         /* DC's rIDSet object */
1342         /* Perform this check only when it does exist - this is needed in order
1343          * to don't let existing provisions break, and to delete . */
1344         ret = samdb_rid_set_dn(ldb, ac, &dn);
1345         if ((ret != LDB_SUCCESS) && (ret != LDB_ERR_NO_SUCH_ATTRIBUTE)
1346             && (ret != LDB_ERR_NO_SUCH_OBJECT)) {
1347                 ldb_asprintf_errstring(ldb, "objectclass: Unable to determine if %s, is this DC's rIDSet object: %s ",
1348                                        ldb_dn_get_linearized(ac->req->op.del.dn),
1349                                        ldb_errstring(ldb));
1350                 return ret;
1351         }
1352         if (ret == LDB_SUCCESS) {
1353                 if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1354                         talloc_free(dn);
1355                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1356                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1357                         return LDB_ERR_UNWILLING_TO_PERFORM;
1358                 }
1359                 talloc_free(dn);
1360         }
1361
1362         /* Only trusted request from system account are allowed to delete
1363          * deleted objects.
1364          */
1365         if (ldb_msg_check_string_attribute(ac->search_res->message, "isDeleted", "TRUE") &&
1366                         (ldb_req_is_untrusted(ac->req) ||
1367                                 !dsdb_module_am_system(ac->module))) {
1368                 ldb_asprintf_errstring(ldb, "Delete of '%s' failed",
1369                                                 ldb_dn_get_linearized(ac->req->op.del.dn));
1370                 return LDB_ERR_UNWILLING_TO_PERFORM;
1371         }
1372
1373         /* crossRef objects regarding config, schema and default domain NCs */
1374         if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1375                                  "crossRef") != NULL) {
1376                 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1377                                              "nCName");
1378                 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1379                     (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0)) {
1380                         talloc_free(dn);
1381
1382                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the main or configuration partition!",
1383                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1384                         return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
1385                 }
1386                 if (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0) {
1387                         talloc_free(dn);
1388
1389                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the schema partition!",
1390                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1391                         return LDB_ERR_UNWILLING_TO_PERFORM;
1392                 }
1393                 talloc_free(dn);
1394         }
1395
1396         /* systemFlags */
1397
1398         systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1399                                                "systemFlags", 0);
1400         if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1401                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1402                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1403                 return LDB_ERR_UNWILLING_TO_PERFORM;
1404         }
1405
1406         /* isCriticalSystemObject - but this only applies on tree delete
1407          * operations - MS-ADTS 3.1.1.5.5.7.2 */
1408         if (ldb_request_get_control(ac->req, LDB_CONTROL_TREE_DELETE_OID) != NULL) {
1409                 isCriticalSystemObject = ldb_msg_find_attr_as_bool(ac->search_res->message,
1410                                                                    "isCriticalSystemObject", false);
1411                 if (isCriticalSystemObject) {
1412                         /*
1413                          * Following the explanation from Microsoft
1414                          * https://lists.samba.org/archive/cifs-protocol/2011-August/002046.html
1415                          * "I finished the investigation on this behavior.
1416                          * As per MS-ADTS 3.1.5.5.7.2 , when a tree deletion is performed ,
1417                          * every object in the tree will be checked to see if it has isCriticalSystemObject
1418                          * set to TRUE, including the root node on which the delete operation is performed
1419                          * But there is an exception  if the root object is a SAM specific objects(3.1.1.5.2.3 MS-ADTS)
1420                          * Its deletion is done through SAM manager and isCriticalSystemObject attribute is not checked
1421                          * The root node of the tree delete in your case is CN=ARES,OU=Domain Controllers,DC=w2k8r2,DC=home,DC=matws,DC=net
1422                          * which is a SAM object  with  user class.  Therefore the tree deletion is performed without any error
1423                          */
1424
1425                         if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "group") == NULL &&
1426                             samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samDomain") == NULL &&
1427                             samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "samServer") == NULL &&
1428                             samdb_find_attribute(ldb, ac->search_res->message, "objectClass", "user") == NULL) {
1429                                         ldb_asprintf_errstring(ldb,
1430                                                "objectclass: Cannot tree-delete %s, it's a critical system object!",
1431                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1432                         return LDB_ERR_UNWILLING_TO_PERFORM;
1433                         }
1434                 }
1435         }
1436
1437         return ldb_next_request(ac->module, ac->req);
1438 }
1439
1440 static int objectclass_init(struct ldb_module *module)
1441 {
1442         struct ldb_context *ldb = ldb_module_get_ctx(module);
1443         int ret;
1444
1445         /* Init everything else */
1446         ret = ldb_next_init(module);
1447         if (ret != LDB_SUCCESS) {
1448                 return ret;
1449         }
1450
1451         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1452         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1453
1454         ret = ldb_mod_register_control(module, LDB_CONTROL_RODC_DCPROMO_OID);
1455         if (ret != LDB_SUCCESS) {
1456                 ldb_debug(ldb, LDB_DEBUG_ERROR,
1457                           "objectclass_init: Unable to register control DCPROMO with rootdse\n");
1458                 return ldb_operr(ldb);
1459         }
1460
1461         return ret;
1462 }
1463
1464 static const struct ldb_module_ops ldb_objectclass_module_ops = {
1465         .name           = "objectclass",
1466         .add            = objectclass_add,
1467         .modify         = objectclass_modify,
1468         .rename         = objectclass_rename,
1469         .del            = objectclass_delete,
1470         .init_context   = objectclass_init
1471 };
1472
1473 int ldb_objectclass_module_init(const char *version)
1474 {
1475         LDB_MODULE_CHECK_VERSION(version);
1476         return ldb_register_module(&ldb_objectclass_module_ops);
1477 }