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