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