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