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