s4:objectclass LDB module - "add operation" - implement "objectCategory" validation
[samba.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2006-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6    Copyright (C) Matthias Dieter Wallnöfer 2010
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         if (ret != LDB_SUCCESS) {
427                 return ret;
428         }
429
430         ac->step_fn = objectclass_do_add;
431
432         return ldb_next_request(ac->module, search_req);
433 }
434
435 static int objectclass_do_add(struct oc_context *ac)
436 {
437         struct ldb_context *ldb;
438         struct ldb_request *add_req;
439         struct ldb_message_element *objectclass_element, *el;
440         struct ldb_message *msg;
441         TALLOC_CTX *mem_ctx;
442         struct class_list *sorted, *current;
443         const char *rdn_name = NULL;
444         char *value;
445         const struct dsdb_class *objectclass;
446         struct ldb_dn *objectcategory;
447         int32_t systemFlags = 0;
448         int ret;
449
450         ldb = ldb_module_get_ctx(ac->module);
451
452         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
453
454         /* Check if we have a valid parent - this check is needed since
455          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
456         if (ac->search_res == NULL) {
457                 unsigned int instanceType;
458
459                 /* An add operation on partition DNs without "NC-add" operation
460                  * isn't allowed. */
461                 instanceType = ldb_msg_find_attr_as_uint(ac->req->op.add.message,
462                                                          "instanceType", 0);
463                 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
464                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
465                                                ldb_dn_get_linearized(msg->dn));
466                         return LDB_ERR_NO_SUCH_OBJECT;
467                 }
468
469                 /* Don't keep any error messages - we've to add a partition */
470                 ldb_set_errstring(ldb, NULL);
471         } else {
472                 /* Fix up the DN to be in the standard form, taking
473                  * particular care to match the parent DN */
474                 ret = fix_dn(ldb, msg,
475                              ac->req->op.add.message->dn,
476                              ac->search_res->message->dn,
477                              &msg->dn);
478                 if (ret != LDB_SUCCESS) {
479                         ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
480                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
481                         return ret;
482                 }
483         }
484
485         mem_ctx = talloc_new(ac);
486         if (mem_ctx == NULL) {
487                 return ldb_oom(ldb);
488         }
489
490         if (ac->schema != NULL) {
491                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
492                 if (!objectclass_element) {
493                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, no objectclass specified!",
494                                                ldb_dn_get_linearized(msg->dn));
495                         talloc_free(mem_ctx);
496                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
497                 }
498
499                 /* Here we do now get the "objectClass" list from the
500                  * database. */
501                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
502                                        objectclass_element, &sorted);
503                 if (ret != LDB_SUCCESS) {
504                         talloc_free(mem_ctx);
505                         return ret;
506                 }
507                 
508                 ldb_msg_remove_element(msg, objectclass_element);
509
510                 /* Well, now we shouldn't find any additional "objectClass"
511                  * message element (required by the AD specification). */
512                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
513                 if (objectclass_element != NULL) {
514                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, only one 'objectclass' attribute specification is allowed!",
515                                                ldb_dn_get_linearized(msg->dn));
516                         talloc_free(mem_ctx);
517                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
518                 }
519
520                 /* We must completely replace the existing objectClass entry,
521                  * because we need it sorted. */
522                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
523                 if (ret != LDB_SUCCESS) {
524                         talloc_free(mem_ctx);
525                         return ret;
526                 }
527
528                 /* Move from the linked list back into an ldb msg */
529                 for (current = sorted; current; current = current->next) {
530                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
531                         if (value == NULL) {
532                                 talloc_free(mem_ctx);
533                                 return ldb_oom(ldb);
534                         }
535                         ret = ldb_msg_add_string(msg, "objectClass", value);
536                         if (ret != LDB_SUCCESS) {
537                                 ldb_set_errstring(ldb,
538                                                   "objectclass: could not re-add sorted "
539                                                   "objectclass to modify msg");
540                                 talloc_free(mem_ctx);
541                                 return ret;
542                         }
543                 }
544
545                 talloc_free(mem_ctx);
546
547                 /* Retrive the message again so get_last_structural_class works */
548                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
549
550                 /* Make sure its valid to add an object of this type */
551                 objectclass = get_last_structural_class(ac->schema,
552                                                         objectclass_element);
553                 if(objectclass == NULL) {
554                         ldb_asprintf_errstring(ldb,
555                                                "Failed to find a structural class for %s",
556                                                ldb_dn_get_linearized(msg->dn));
557                         return LDB_ERR_UNWILLING_TO_PERFORM;
558                 }
559
560                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
561                 if (objectclass->rDNAttID
562                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
563                         ldb_asprintf_errstring(ldb,
564                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
565                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
566                         return LDB_ERR_NAMING_VIOLATION;
567                 }
568
569                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
570                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
571                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
572                         return LDB_ERR_UNWILLING_TO_PERFORM;
573                 }
574
575                 if (((strcmp(objectclass->lDAPDisplayName, "secret") == 0) ||
576                      (strcmp(objectclass->lDAPDisplayName, "trustedDomain") == 0)) &&
577                     !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
578                         ldb_asprintf_errstring(ldb, "objectClass %s is LSA-specific, rejecting creation of %s",
579                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
580                         return LDB_ERR_UNWILLING_TO_PERFORM;
581                 }
582
583                 if (ac->search_res && ac->search_res->message) {
584                         struct ldb_message_element *oc_el
585                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
586
587                         bool allowed_class = false;
588                         unsigned int i, j;
589                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
590                                 const struct dsdb_class *sclass;
591
592                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
593                                                                                &oc_el->values[i]);
594                                 if (!sclass) {
595                                         /* We don't know this class?  what is going on? */
596                                         continue;
597                                 }
598                                 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
599                                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
600                                                 allowed_class = true;
601                                                 break;
602                                         }
603                                 }
604                         }
605
606                         if (!allowed_class) {
607                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
608                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
609                                 return LDB_ERR_NAMING_VIOLATION;
610                         }
611                 }
612
613                 objectcategory = ldb_msg_find_attr_as_dn(ldb, ac, msg,
614                                                          "objectCategory");
615                 if (objectcategory == NULL) {
616                         struct dsdb_extended_dn_store_format *dn_format =
617                                         talloc_get_type(ldb_module_get_private(ac->module),
618                                                         struct dsdb_extended_dn_store_format);
619                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
620                                 /* Strip off extended components */
621                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
622                                                                objectclass->defaultObjectCategory);
623                                 value = ldb_dn_alloc_linearized(msg, dn);
624                                 talloc_free(dn);
625                         } else {
626                                 value = talloc_strdup(msg,
627                                                       objectclass->defaultObjectCategory);
628                         }
629                         if (value == NULL) {
630                                 return ldb_oom(ldb);
631                         }
632
633                         ret = ldb_msg_add_string(msg, "objectCategory", value);
634                         if (ret != LDB_SUCCESS) {
635                                 return ret;
636                         }
637                 } else {
638                         const struct dsdb_class *ocClass =
639                                         dsdb_class_by_cn_ldb_val(ac->schema,
640                                                                  ldb_dn_get_rdn_val(objectcategory));
641                         if (ocClass != NULL) {
642                                 struct ldb_dn *dn = ldb_dn_new(ac, ldb,
643                                                                ocClass->defaultObjectCategory);
644                                 if (ldb_dn_compare(objectcategory, dn) != 0) {
645                                         ocClass = NULL;
646                                 }
647                         }
648                         talloc_free(objectcategory);
649                         if (ocClass == NULL) {
650                                 ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, 'objectCategory' attribute invalid!",
651                                                        ldb_dn_get_linearized(msg->dn));
652                                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
653                         }
654                 }
655
656                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
657                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
658                                                 "TRUE");
659                 }
660
661                 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
662                 el = ldb_msg_find_element(msg, "systemFlags");
663
664                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
665
666                 if (el) {
667                         /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
668                         /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
669                         ldb_msg_remove_element(msg, el);
670                 }
671
672                 /* This flag is only allowed on attributeSchema objects */
673                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
674                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
675                 }
676
677                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
678                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
679                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
680                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
681                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
682                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
683
684                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
685                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
686                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
687                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
688                 }
689
690                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
691
692                 if (el || systemFlags != 0) {
693                         samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
694                 }
695         }
696         ret = ldb_msg_sanity_check(ldb, msg);
697
698         if (ret != LDB_SUCCESS) {
699                 return ret;
700         }
701
702         ret = ldb_build_add_req(&add_req, ldb, ac,
703                                 msg,
704                                 ac->req->controls,
705                                 ac, oc_op_callback,
706                                 ac->req);
707         if (ret != LDB_SUCCESS) {
708                 return ret;
709         }
710
711         /* perform the add */
712         return ldb_next_request(ac->module, add_req);
713 }
714
715 static int oc_modify_callback(struct ldb_request *req,
716                                 struct ldb_reply *ares);
717 static int objectclass_do_mod(struct oc_context *ac);
718
719 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
720 {
721         struct ldb_context *ldb = ldb_module_get_ctx(module);
722         struct ldb_message_element *objectclass_element;
723         struct ldb_message *msg;
724         struct ldb_request *down_req;
725         struct oc_context *ac;
726         bool oc_changes = false;
727         int ret;
728
729         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
730
731         /* do not manipulate our control entries */
732         if (ldb_dn_is_special(req->op.mod.message->dn)) {
733                 return ldb_next_request(module, req);
734         }
735
736         /* As with the "real" AD we don't accept empty messages */
737         if (req->op.mod.message->num_elements == 0) {
738                 ldb_set_errstring(ldb, "objectclass: modify message must have "
739                                        "elements/attributes!");
740                 return LDB_ERR_UNWILLING_TO_PERFORM;
741         }
742
743         ac = oc_init_context(module, req);
744         if (ac == NULL) {
745                 return ldb_operr(ldb);
746         }
747
748         /* Without schema, there isn't much to do here */
749         if (ac->schema == NULL) {
750                 talloc_free(ac);
751                 return ldb_next_request(module, req);
752         }
753
754         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
755         if (msg == NULL) {
756                 return ldb_operr(ldb);
757         }
758
759         /* For now change everything except the objectclasses */
760
761         objectclass_element = ldb_msg_find_element(msg, "objectClass");
762         if (objectclass_element != NULL) {
763                 ldb_msg_remove_attr(msg, "objectClass");
764                 oc_changes = true;
765         }
766
767         ret = ldb_build_mod_req(&down_req, ldb, ac,
768                                 msg,
769                                 req->controls, ac,
770                                 oc_changes ? oc_modify_callback : oc_op_callback,
771                                 req);
772         if (ret != LDB_SUCCESS) {
773                 return ret;
774         }
775
776         return ldb_next_request(module, down_req);
777 }
778
779 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
780 {
781         static const char * const attrs[] = { "objectClass", NULL };
782         struct ldb_context *ldb;
783         struct ldb_request *search_req;
784         struct oc_context *ac;
785         int ret;
786
787         ac = talloc_get_type(req->context, struct oc_context);
788         ldb = ldb_module_get_ctx(ac->module);
789
790         if (!ares) {
791                 return ldb_module_done(ac->req, NULL, NULL,
792                                         LDB_ERR_OPERATIONS_ERROR);
793         }
794
795         if (ares->type == LDB_REPLY_REFERRAL) {
796                 return ldb_module_send_referral(ac->req, ares->referral);
797         }
798
799         if (ares->error != LDB_SUCCESS) {
800                 return ldb_module_done(ac->req, ares->controls,
801                                         ares->response, ares->error);
802         }
803
804         if (ares->type != LDB_REPLY_DONE) {
805                 talloc_free(ares);
806                 return ldb_module_done(ac->req, NULL, NULL,
807                                         LDB_ERR_OPERATIONS_ERROR);
808         }
809
810         talloc_free(ares);
811
812         /* this looks up the real existing object for fetching some important
813          * informations (objectclasses) */
814         ret = ldb_build_search_req(&search_req, ldb,
815                                    ac, ac->req->op.mod.message->dn,
816                                    LDB_SCOPE_BASE,
817                                    "(objectClass=*)",
818                                    attrs, NULL, 
819                                    ac, get_search_callback,
820                                    ac->req);
821         if (ret != LDB_SUCCESS) {
822                 return ldb_module_done(ac->req, NULL, NULL, ret);
823         }
824
825         ac->step_fn = objectclass_do_mod;
826
827         ret = ldb_next_request(ac->module, search_req);
828         if (ret != LDB_SUCCESS) {
829                 return ldb_module_done(ac->req, NULL, NULL, ret);
830         }
831
832         return LDB_SUCCESS;
833 }
834
835 static int objectclass_do_mod(struct oc_context *ac)
836 {
837         struct ldb_context *ldb;
838         struct ldb_request *mod_req;
839         char *value;
840         struct ldb_message_element *oc_el_entry, *oc_el_change;
841         struct ldb_val *vals;
842         struct ldb_message *msg;
843         TALLOC_CTX *mem_ctx;
844         struct class_list *sorted, *current;
845         const struct dsdb_class *objectclass;
846         unsigned int i, j;
847         bool found, replace = false;
848         int ret;
849
850         ldb = ldb_module_get_ctx(ac->module);
851
852         /* we should always have a valid entry when we enter here */
853         if (ac->search_res == NULL) {
854                 return ldb_operr(ldb);
855         }
856
857         oc_el_entry = ldb_msg_find_element(ac->search_res->message,
858                                            "objectClass");
859         if (oc_el_entry == NULL) {
860                 /* existing entry without a valid object class? */
861                 return ldb_operr(ldb);
862         }
863
864         oc_el_change = ldb_msg_find_element(ac->req->op.mod.message,
865                                             "objectClass");
866         if (oc_el_change == NULL) {
867                 /* we should have an objectclass change operation */
868                 return ldb_operr(ldb);
869         }
870
871         /* use a new message structure */
872         msg = ldb_msg_new(ac);
873         if (msg == NULL) {
874                 return ldb_oom(ldb);
875         }
876
877         msg->dn = ac->req->op.mod.message->dn;
878
879         mem_ctx = talloc_new(ac);
880         if (mem_ctx == NULL) {
881                 return ldb_oom(ldb);
882         }
883
884         switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
885         case LDB_FLAG_MOD_ADD:
886                 /* Merge the two message elements */
887                 for (i = 0; i < oc_el_change->num_values; i++) {
888                         for (j = 0; j < oc_el_entry->num_values; j++) {
889                                 if (strcasecmp((char *)oc_el_change->values[i].data,
890                                                (char *)oc_el_entry->values[j].data) == 0) {
891                                         /* we cannot add an already existing object class */
892                                         talloc_free(mem_ctx);
893                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
894                                 }
895                         }
896                         /* append the new object class value - code was copied
897                          * from "ldb_msg_add_value" */
898                         vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
899                                               struct ldb_val,
900                                               oc_el_entry->num_values + 1);
901                         if (vals == NULL) {
902                                 talloc_free(mem_ctx);
903                                 return ldb_oom(ldb);
904                         }
905                         oc_el_entry->values = vals;
906                         oc_el_entry->values[oc_el_entry->num_values] =
907                                 oc_el_change->values[i];
908                         ++(oc_el_entry->num_values);
909                 }
910
911                 objectclass = get_last_structural_class(ac->schema,
912                                                         oc_el_change);
913                 if (objectclass != NULL) {
914                         /* we cannot add a new structural object class */
915                         talloc_free(mem_ctx);
916                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
917                 }
918
919                 /* Now do the sorting */
920                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
921                                        oc_el_entry, &sorted);
922                 if (ret != LDB_SUCCESS) {
923                         talloc_free(mem_ctx);
924                         return ret;
925                 }
926
927                 break;
928
929         case LDB_FLAG_MOD_REPLACE:
930                 /* Do the sorting for the change message element */
931                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
932                                        oc_el_change, &sorted);
933                 if (ret != LDB_SUCCESS) {
934                         talloc_free(mem_ctx);
935                         return ret;
936                 }
937
938                 /* this is a replace */
939                 replace = true;
940
941                 break;
942
943         case LDB_FLAG_MOD_DELETE:
944                 /* get the actual top-most structural objectclass */
945                 objectclass = get_last_structural_class(ac->schema,
946                                                         oc_el_entry);
947                 if (objectclass == NULL) {
948                         talloc_free(mem_ctx);
949                         return ldb_operr(ldb);
950                 }
951
952                 /* Merge the two message elements */
953                 for (i = 0; i < oc_el_change->num_values; i++) {
954                         found = false;
955                         for (j = 0; j < oc_el_entry->num_values; j++) {
956                                 if (strcasecmp((char *)oc_el_change->values[i].data,
957                                                (char *)oc_el_entry->values[j].data) == 0) {
958                                         found = true;
959                                         /* delete the object class value -
960                                          * code was copied from
961                                          * "ldb_msg_remove_element" */
962                                         if (j != oc_el_entry->num_values - 1) {
963                                                 memmove(&oc_el_entry->values[j],
964                                                         &oc_el_entry->values[j+1],
965                                                         ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
966                                         }
967                                         --(oc_el_entry->num_values);
968                                         break;
969                                 }
970                         }
971                         if (!found) {
972                                 /* we cannot delete a not existing object class */
973                                 talloc_free(mem_ctx);
974                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
975                         }
976                 }
977
978                 /* Make sure that the top-most structural objectclass wasn't
979                  * deleted */
980                 found = false;
981                 for (i = 0; i < oc_el_entry->num_values; i++) {
982                         if (strcasecmp(objectclass->lDAPDisplayName,
983                             (char *)oc_el_entry->values[i].data) == 0) {
984                                 found = true; break;
985                         }
986                 }
987                 if (!found) {
988                         talloc_free(mem_ctx);
989                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
990                 }
991
992
993                 /* Now do the sorting */
994                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
995                                        oc_el_entry, &sorted);
996                 if (ret != LDB_SUCCESS) {
997                         talloc_free(mem_ctx);
998                         return ret;
999                 }
1000
1001                 break;
1002         }
1003
1004         ret = ldb_msg_add_empty(msg, "objectClass",
1005                                 LDB_FLAG_MOD_REPLACE, &oc_el_change);
1006         if (ret != LDB_SUCCESS) {
1007                 ldb_oom(ldb);
1008                 talloc_free(mem_ctx);
1009                 return ret;
1010         }
1011
1012         /* Move from the linked list back into an ldb msg */
1013         for (current = sorted; current; current = current->next) {
1014                 value = talloc_strdup(msg,
1015                                       current->objectclass->lDAPDisplayName);
1016                 if (value == NULL) {
1017                         talloc_free(mem_ctx);
1018                         return ldb_oom(ldb);
1019                 }
1020                 ret = ldb_msg_add_string(msg, "objectClass", value);
1021                 if (ret != LDB_SUCCESS) {
1022                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1023                         talloc_free(mem_ctx);
1024                         return ret;
1025                 }
1026         }
1027
1028         talloc_free(mem_ctx);
1029
1030         if (replace) {
1031                 /* Well, on replace we are nearly done: we have to test if
1032                  * the change and entry message element are identically. We
1033                  * can use "ldb_msg_element_compare" since now the specified
1034                  * objectclasses match for sure in case. */
1035                 ret = ldb_msg_element_compare(oc_el_entry, oc_el_change);
1036                 if (ret == 0) {
1037                         ret = ldb_msg_element_compare(oc_el_change,
1038                                                       oc_el_entry);
1039                 }
1040                 if (ret == 0) {
1041                         /* they are the same so we are done in this case */
1042                         return ldb_module_done(ac->req, NULL, NULL,
1043                                                LDB_SUCCESS);
1044                 } else {
1045                         /* they're not exactly the same */
1046                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1047                 }
1048         }
1049
1050         /* in the other cases we have the real change left to do */
1051
1052         ret = ldb_msg_sanity_check(ldb, msg);
1053         if (ret != LDB_SUCCESS) {
1054                 return ret;
1055         }
1056
1057         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1058                                 msg,
1059                                 ac->req->controls,
1060                                 ac, oc_op_callback,
1061                                 ac->req);
1062         if (ret != LDB_SUCCESS) {
1063                 return ret;
1064         }
1065
1066         return ldb_next_request(ac->module, mod_req);
1067 }
1068
1069 static int objectclass_do_rename(struct oc_context *ac);
1070
1071 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1072 {
1073         static const char * const attrs[] = { "objectClass", NULL };
1074         struct ldb_context *ldb;
1075         struct ldb_request *search_req;
1076         struct oc_context *ac;
1077         struct ldb_dn *parent_dn;
1078         int ret;
1079
1080         ldb = ldb_module_get_ctx(module);
1081
1082         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1083
1084         /* do not manipulate our control entries */
1085         if (ldb_dn_is_special(req->op.rename.newdn)) {
1086                 return ldb_next_request(module, req);
1087         }
1088
1089         ac = oc_init_context(module, req);
1090         if (ac == NULL) {
1091                 return ldb_operr(ldb);
1092         }
1093
1094         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1095         if (parent_dn == NULL) {
1096                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1097                                        ldb_dn_get_linearized(req->op.rename.olddn));
1098                 return LDB_ERR_NO_SUCH_OBJECT;
1099         }
1100
1101         /* this looks up the parent object for fetching some important
1102          * informations (objectclasses, DN normalisation...) */
1103         ret = ldb_build_search_req(&search_req, ldb,
1104                                    ac, parent_dn, LDB_SCOPE_BASE,
1105                                    "(objectClass=*)",
1106                                    attrs, NULL,
1107                                    ac, get_search_callback,
1108                                    req);
1109         if (ret != LDB_SUCCESS) {
1110                 return ret;
1111         }
1112
1113         /* we have to add the show deleted control, as otherwise DRS
1114            deletes will be refused as we will think the target parent
1115            does not exist */
1116         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1117
1118         if (ret != LDB_SUCCESS) {
1119                 return ret;
1120         }
1121
1122         ac->step_fn = objectclass_do_rename;
1123
1124         return ldb_next_request(ac->module, search_req);
1125 }
1126
1127 static int objectclass_do_rename2(struct oc_context *ac);
1128
1129 static int objectclass_do_rename(struct oc_context *ac)
1130 {
1131         static const char * const attrs[] = { "objectClass", NULL };
1132         struct ldb_context *ldb;
1133         struct ldb_request *search_req;
1134         int ret;
1135
1136         ldb = ldb_module_get_ctx(ac->module);
1137
1138         /* Check if we have a valid parent - this check is needed since
1139          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1140         if (ac->search_res == NULL) {
1141                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1142                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1143                 return LDB_ERR_OTHER;
1144         }
1145
1146         /* now assign "search_res2" to the parent entry to have "search_res"
1147          * free for another lookup */
1148         ac->search_res2 = ac->search_res;
1149         ac->search_res = NULL;
1150
1151         /* this looks up the real existing object for fetching some important
1152          * informations (objectclasses) */
1153         ret = ldb_build_search_req(&search_req, ldb,
1154                                    ac, ac->req->op.rename.olddn,
1155                                    LDB_SCOPE_BASE,
1156                                    "(objectClass=*)",
1157                                    attrs, NULL,
1158                                    ac, get_search_callback,
1159                                    ac->req);
1160         if (ret != LDB_SUCCESS) {
1161                 return ret;
1162         }
1163
1164         ac->step_fn = objectclass_do_rename2;
1165
1166         return ldb_next_request(ac->module, search_req);
1167 }
1168
1169 static int objectclass_do_rename2(struct oc_context *ac)
1170 {
1171         struct ldb_context *ldb;
1172         struct ldb_request *rename_req;
1173         struct ldb_dn *fixed_dn;
1174         int ret;
1175
1176         ldb = ldb_module_get_ctx(ac->module);
1177
1178         /* Check if we have a valid entry - this check is needed since
1179          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1180         if (ac->search_res == NULL) {
1181                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1182                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1183                 return LDB_ERR_NO_SUCH_OBJECT;
1184         }
1185
1186         if (ac->schema != NULL) {
1187                 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1188                 const struct dsdb_class *objectclass;
1189                 const char *rdn_name;
1190                 bool allowed_class = false;
1191                 unsigned int i, j;
1192
1193                 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1194                                                    "objectClass");
1195                 if (oc_el_entry == NULL) {
1196                         /* existing entry without a valid object class? */
1197                         return ldb_operr(ldb);
1198                 }
1199                 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1200                 if (objectclass == NULL) {
1201                         /* existing entry without a valid object class? */
1202                         return ldb_operr(ldb);
1203                 }
1204
1205                 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1206                 if ((objectclass->rDNAttID != NULL) &&
1207                     (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1208                         ldb_asprintf_errstring(ldb,
1209                                                "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1210                                                rdn_name,
1211                                                objectclass->lDAPDisplayName,
1212                                                objectclass->rDNAttID);
1213                         return LDB_ERR_UNWILLING_TO_PERFORM;
1214                 }
1215
1216                 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1217                                                     "objectClass");
1218                 if (oc_el_parent == NULL) {
1219                         /* existing entry without a valid object class? */
1220                         return ldb_operr(ldb);
1221                 }
1222
1223                 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1224                         const struct dsdb_class *sclass;
1225
1226                         sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1227                                                                        &oc_el_parent->values[i]);
1228                         if (!sclass) {
1229                                 /* We don't know this class?  what is going on? */
1230                                 continue;
1231                         }
1232                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1233                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1234                                         allowed_class = true;
1235                                         break;
1236                                 }
1237                         }
1238                 }
1239
1240                 if (!allowed_class) {
1241                         ldb_asprintf_errstring(ldb,
1242                                                "objectclass: structural objectClass %s is not a valid child class for %s",
1243                                                objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1244                         return LDB_ERR_NAMING_VIOLATION;
1245                 }
1246         }
1247
1248         /* Ensure we are not trying to rename it to be a child of itself */
1249         if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1250                                  ac->req->op.rename.newdn) == 0)  &&
1251             (ldb_dn_compare(ac->req->op.rename.olddn,
1252                             ac->req->op.rename.newdn) != 0)) {
1253                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1254                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1255                 return LDB_ERR_UNWILLING_TO_PERFORM;
1256         }
1257
1258         /* Fix up the DN to be in the standard form, taking
1259          * particular care to match the parent DN */
1260         ret = fix_dn(ldb, ac,
1261                      ac->req->op.rename.newdn,
1262                      ac->search_res2->message->dn,
1263                      &fixed_dn);
1264         if (ret != LDB_SUCCESS) {
1265                 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1266                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1267                 return ret;
1268
1269         }
1270
1271         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1272                                    ac->req->op.rename.olddn, fixed_dn,
1273                                    ac->req->controls,
1274                                    ac, oc_op_callback,
1275                                    ac->req);
1276         if (ret != LDB_SUCCESS) {
1277                 return ret;
1278         }
1279
1280         /* perform the rename */
1281         return ldb_next_request(ac->module, rename_req);
1282 }
1283
1284 static int objectclass_do_delete(struct oc_context *ac);
1285
1286 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1287 {
1288         static const char * const attrs[] = { "nCName", "objectClass",
1289                                               "systemFlags", NULL };
1290         struct ldb_context *ldb;
1291         struct ldb_request *search_req;
1292         struct oc_context *ac;
1293         int ret;
1294
1295         ldb = ldb_module_get_ctx(module);
1296
1297         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1298
1299         /* do not manipulate our control entries */
1300         if (ldb_dn_is_special(req->op.del.dn)) {
1301                 return ldb_next_request(module, req);
1302         }
1303
1304         /* Bypass the constraint checks when we do have the "RELAX" control
1305          * set. */
1306         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1307                 return ldb_next_request(module, req);
1308         }
1309
1310         ac = oc_init_context(module, req);
1311         if (ac == NULL) {
1312                 return ldb_operr(ldb);
1313         }
1314
1315         /* this looks up the entry object for fetching some important
1316          * informations (object classes, system flags...) */
1317         ret = ldb_build_search_req(&search_req, ldb,
1318                                    ac, req->op.del.dn, LDB_SCOPE_BASE,
1319                                    "(objectClass=*)",
1320                                    attrs, NULL,
1321                                    ac, get_search_callback,
1322                                    req);
1323         if (ret != LDB_SUCCESS) {
1324                 return ret;
1325         }
1326
1327         ac->step_fn = objectclass_do_delete;
1328
1329         return ldb_next_request(ac->module, search_req);
1330 }
1331
1332 static int objectclass_do_delete(struct oc_context *ac)
1333 {
1334         struct ldb_context *ldb;
1335         struct ldb_dn *dn;
1336         int32_t systemFlags;
1337         int ret;
1338
1339         ldb = ldb_module_get_ctx(ac->module);
1340
1341         /* Check if we have a valid entry - this check is needed since
1342          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1343         if (ac->search_res == NULL) {
1344                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1345                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1346                 return LDB_ERR_NO_SUCH_OBJECT;
1347         }
1348
1349         /* DC's ntDSDSA object */
1350         if (ldb_dn_compare(ac->req->op.del.dn, samdb_ntds_settings_dn(ldb)) == 0) {
1351                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's ntDSDSA object!",
1352                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1353                 return LDB_ERR_UNWILLING_TO_PERFORM;
1354         }
1355
1356         /* DC's rIDSet object */
1357         ret = samdb_rid_set_dn(ldb, ac, &dn);
1358         if (ret != LDB_SUCCESS) {
1359                 return ret;
1360         }
1361
1362         if (ldb_dn_compare(ac->req->op.del.dn, dn) == 0) {
1363                 talloc_free(dn);
1364                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's the DC's rIDSet object!",
1365                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1366                 return LDB_ERR_UNWILLING_TO_PERFORM;
1367         }
1368
1369         talloc_free(dn);
1370
1371         /* crossRef objects regarding config, schema and default domain NCs */
1372         if (samdb_find_attribute(ldb, ac->search_res->message, "objectClass",
1373                                  "crossRef") != NULL) {
1374                 dn = ldb_msg_find_attr_as_dn(ldb, ac, ac->search_res->message,
1375                                              "nCName");
1376                 if ((ldb_dn_compare(dn, ldb_get_default_basedn(ldb)) == 0) ||
1377                     (ldb_dn_compare(dn, ldb_get_config_basedn(ldb)) == 0) ||
1378                     (ldb_dn_compare(dn, ldb_get_schema_basedn(ldb)) == 0)) {
1379                         talloc_free(dn);
1380
1381                         ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it's a crossRef object to the three main partitions!",
1382                                                ldb_dn_get_linearized(ac->req->op.del.dn));
1383                         return LDB_ERR_UNWILLING_TO_PERFORM;
1384                 }
1385                 talloc_free(dn);
1386         }
1387
1388         /* systemFlags */
1389
1390         systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1391                                                "systemFlags", 0);
1392         if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1393                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1394                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1395                 return LDB_ERR_UNWILLING_TO_PERFORM;
1396         }
1397
1398         return ldb_next_request(ac->module, ac->req);
1399 }
1400
1401 static int objectclass_init(struct ldb_module *module)
1402 {
1403         struct ldb_context *ldb = ldb_module_get_ctx(module);
1404         int ret;
1405
1406         /* Init everything else */
1407         ret = ldb_next_init(module);
1408         if (ret != LDB_SUCCESS) {
1409                 return ret;
1410         }
1411         
1412         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1413         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1414
1415         return ret;
1416 }
1417
1418 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1419         .name           = "objectclass",
1420         .add            = objectclass_add,
1421         .modify         = objectclass_modify,
1422         .rename         = objectclass_rename,
1423         .del            = objectclass_delete,
1424         .init_context   = objectclass_init
1425 };