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