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