s4:objectclass LDB module - disable delete operations when "SYSTEM_FLAG_DISALLOW_DELE...
[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                         ldb_oom(ldb);
140                         return LDB_ERR_OPERATIONS_ERROR;
141                 }
142                 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
143                 if (!current->objectclass) {
144                         ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema", 
145                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
146                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
147                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
148                 } else if (current->objectclass->isDefunct) {
149                         ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects", 
150                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
151                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
152                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
153                 }
154
155                 /* Don't add top to list, we will do that later */
156                 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
157                         DLIST_ADD_END(unsorted, current, struct class_list *);
158                 }
159         }
160
161         /* Add top here, to prevent duplicates */
162         current = talloc(mem_ctx, struct class_list);
163         current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
164         DLIST_ADD_END(sorted, current, struct class_list *);
165
166
167         /* For each object:  find parent chain */
168         for (current = unsorted; schema && current; current = current->next) {
169                 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
170                         if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
171                                 break;
172                         }
173                 }
174                 /* If we didn't get to the end of the list, we need to add this parent */
175                 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
176                         continue;
177                 }
178
179                 new_parent = talloc(mem_ctx, struct class_list);
180                 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
181                 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
182         }
183
184         do
185         {
186                 lowest = UINT_MAX;
187                 current_lowest = NULL;
188                 for (current = unsorted; schema && current; current = current->next) {
189                         if(current->objectclass->subClass_order < lowest) {
190                                 current_lowest = current;
191                                 lowest = current->objectclass->subClass_order;
192                         }
193                 }
194
195                 if(current_lowest != NULL) {
196                         DLIST_REMOVE(unsorted,current_lowest);
197                         DLIST_ADD_END(sorted,current_lowest, struct class_list *);
198                 }
199         } while(unsorted);
200
201
202         if (!unsorted) {
203                 *sorted_out = sorted;
204                 return LDB_SUCCESS;
205         }
206
207         if (!schema) {
208                 /* If we don't have schema yet, then just merge the lists again */
209                 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
210                 *sorted_out = sorted;
211                 return LDB_SUCCESS;
212         }
213
214         /* This shouldn't happen, and would break MMC, perhaps there
215          * was no 'top', a conflict in the objectClasses or some other
216          * schema error?
217          */
218         ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
219         return LDB_ERR_OBJECT_CLASS_VIOLATION;
220 }
221
222 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
223 {
224         struct ldb_context *ldb;
225         struct oc_context *ac;
226         int ret;
227
228         ac = talloc_get_type(req->context, struct oc_context);
229         ldb = ldb_module_get_ctx(ac->module);
230
231         if (!ares) {
232                 return ldb_module_done(ac->req, NULL, NULL,
233                                         LDB_ERR_OPERATIONS_ERROR);
234         }
235         if (ares->error != LDB_SUCCESS &&
236             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
237                 return ldb_module_done(ac->req, ares->controls,
238                                         ares->response, ares->error);
239         }
240
241         ldb_reset_err_string(ldb);
242
243         switch (ares->type) {
244         case LDB_REPLY_ENTRY:
245                 if (ac->search_res != NULL) {
246                         ldb_set_errstring(ldb, "Too many results");
247                         talloc_free(ares);
248                         return ldb_module_done(ac->req, NULL, NULL,
249                                                 LDB_ERR_OPERATIONS_ERROR);
250                 }
251
252                 ac->search_res = talloc_steal(ac, ares);
253                 break;
254
255         case LDB_REPLY_REFERRAL:
256                 /* ignore */
257                 talloc_free(ares);
258                 break;
259
260         case LDB_REPLY_DONE:
261                 talloc_free(ares);
262                 ret = ac->step_fn(ac);
263                 if (ret != LDB_SUCCESS) {
264                         return ldb_module_done(ac->req, NULL, NULL, ret);
265                 }
266                 break;
267         }
268
269         return LDB_SUCCESS;
270 }
271
272 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
273 {
274         struct oc_context *ac;
275
276         ac = talloc_get_type(req->context, struct oc_context);
277
278         if (!ares) {
279                 return ldb_module_done(ac->req, NULL, NULL,
280                                         LDB_ERR_OPERATIONS_ERROR);
281         }
282
283         if (ares->type == LDB_REPLY_REFERRAL) {
284                 return ldb_module_send_referral(ac->req, ares->referral);
285         }
286
287         if (ares->error != LDB_SUCCESS) {
288                 return ldb_module_done(ac->req, ares->controls,
289                                         ares->response, ares->error);
290         }
291
292         if (ares->type != LDB_REPLY_DONE) {
293                 talloc_free(ares);
294                 return ldb_module_done(ac->req, NULL, NULL,
295                                         LDB_ERR_OPERATIONS_ERROR);
296         }
297
298         return ldb_module_done(ac->req, ares->controls,
299                                 ares->response, ares->error);
300 }
301
302 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
303
304    This should mean that if the parent is:
305     CN=Users,DC=samba,DC=example,DC=com
306    and a proposed child is
307     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
308
309    The resulting DN should be:
310
311     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
312    
313  */
314 static int fix_dn(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_ERR_OPERATIONS_ERROR;
329         }
330
331         /* Create a new child */
332         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
333                 return LDB_ERR_OPERATIONS_ERROR;
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_ERR_OPERATIONS_ERROR;
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_ERR_OPERATIONS_ERROR;
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_ERR_OPERATIONS_ERROR;
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                 ldb_oom(ldb);
422                 return LDB_ERR_OPERATIONS_ERROR;
423         }
424
425         ret = ldb_build_search_req(&search_req, ldb,
426                                    ac, parent_dn, LDB_SCOPE_BASE,
427                                    "(objectClass=*)", parent_attrs,
428                                    NULL,
429                                    ac, get_search_callback,
430                                    req);
431         if (ret != LDB_SUCCESS) {
432                 return ret;
433         }
434
435         ac->step_fn = objectclass_do_add;
436
437         return ldb_next_request(ac->module, search_req);
438 }
439
440 static int objectclass_do_add(struct oc_context *ac)
441 {
442         struct ldb_context *ldb;
443         struct ldb_request *add_req;
444         struct ldb_message_element *objectclass_element, *el;
445         struct ldb_message *msg;
446         TALLOC_CTX *mem_ctx;
447         struct class_list *sorted, *current;
448         const char *rdn_name = NULL;
449         char *value;
450         const struct dsdb_class *objectclass;
451         int32_t systemFlags = 0;
452         int ret;
453
454         ldb = ldb_module_get_ctx(ac->module);
455
456         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
457
458         /* Check if we have a valid parent - this check is needed since
459          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
460         if (ac->search_res == NULL) {
461                 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
462                         /* Allow the tree to be started but don't keep any
463                          * error strings - they're meaningless. */
464                         ldb_set_errstring(ldb, NULL);
465                 } else {
466                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
467                                                ldb_dn_get_linearized(msg->dn));
468                         return LDB_ERR_NO_SUCH_OBJECT;
469                 }
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(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                 ldb_oom(ldb);
487                 return LDB_ERR_OPERATIONS_ERROR;
488         }
489
490         if (ac->schema != NULL) {
491                 /* This is now the objectClass list from the database */
492                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
493
494                 if (!objectclass_element) {
495                         /* Where did it go?  bail now... */
496                         talloc_free(mem_ctx);
497                         return LDB_ERR_OPERATIONS_ERROR;
498                 }
499                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
500                                        objectclass_element, &sorted);
501                 if (ret != LDB_SUCCESS) {
502                         talloc_free(mem_ctx);
503                         return ret;
504                 }
505                 
506                 ldb_msg_remove_attr(msg, "objectClass");
507                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
508                 
509                 if (ret != LDB_SUCCESS) {
510                         talloc_free(mem_ctx);
511                         return ret;
512                 }
513
514                 /* We must completely replace the existing objectClass entry,
515                  * because we need it sorted */
516
517                 /* Move from the linked list back into an ldb msg */
518                 for (current = sorted; current; current = current->next) {
519                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
520                         if (value == NULL) {
521                                 ldb_oom(ldb);
522                                 talloc_free(mem_ctx);
523                                 return LDB_ERR_OPERATIONS_ERROR;
524                         }
525                         ret = ldb_msg_add_string(msg, "objectClass", value);
526                         if (ret != LDB_SUCCESS) {
527                                 ldb_set_errstring(ldb,
528                                                   "objectclass: could not re-add sorted "
529                                                   "objectclass to modify msg");
530                                 talloc_free(mem_ctx);
531                                 return ret;
532                         }
533                 }
534
535                 /* Retrive the message again so get_last_structural_class works */
536                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
537
538                 /* Make sure its valid to add an object of this type */
539                 objectclass = get_last_structural_class(ac->schema,
540                                                         objectclass_element);
541                 if(objectclass == NULL) {
542                         ldb_asprintf_errstring(ldb,
543                                                "Failed to find a structural class for %s",
544                                                ldb_dn_get_linearized(msg->dn));
545                         return LDB_ERR_UNWILLING_TO_PERFORM;
546                 }
547
548                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
549                 if (objectclass->rDNAttID
550                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
551                         ldb_asprintf_errstring(ldb,
552                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
553                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
554                         return LDB_ERR_NAMING_VIOLATION;
555                 }
556
557                 if (ac->search_res && ac->search_res->message) {
558                         struct ldb_message_element *oc_el
559                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
560
561                         bool allowed_class = false;
562                         unsigned int i, j;
563                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
564                                 const struct dsdb_class *sclass;
565
566                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
567                                                                                &oc_el->values[i]);
568                                 if (!sclass) {
569                                         /* We don't know this class?  what is going on? */
570                                         continue;
571                                 }
572                                 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
573                                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
574                                                 allowed_class = true;
575                                                 break;
576                                         }
577                                 }
578                         }
579
580                         if (!allowed_class) {
581                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
582                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
583                                 return LDB_ERR_NAMING_VIOLATION;
584                         }
585                 }
586
587                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
588                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
589                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
590                         return LDB_ERR_UNWILLING_TO_PERFORM;
591                 }
592
593                 if (!ldb_msg_find_element(msg, "objectCategory")) {
594                         struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
595                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
596                                 /* Strip off extended components */
597                                 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
598                                 value = ldb_dn_alloc_linearized(msg, dn);
599                                 talloc_free(dn);
600                         } else {
601                                 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
602                         }
603                         if (value == NULL) {
604                                 ldb_oom(ldb);
605                                 talloc_free(mem_ctx);
606                                 return LDB_ERR_OPERATIONS_ERROR;
607                         }
608                         ldb_msg_add_string(msg, "objectCategory", value);
609                 }
610                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
611                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
612                                                 "TRUE");
613                 }
614
615                 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
616                 el = ldb_msg_find_element(msg, "systemFlags");
617
618                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
619
620                 if (el) {
621                         /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
622                         /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
623                         ldb_msg_remove_element(msg, el);
624                 }
625
626                 /* This flag is only allowed on attributeSchema objects */
627                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
628                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
629                 }
630
631                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
632                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
633                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
634                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
635                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
636                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
637
638                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
639                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
640                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
641                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
642                 }
643
644                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
645
646                 if (el || systemFlags != 0) {
647                         samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
648                 }
649         }
650
651         talloc_free(mem_ctx);
652         ret = ldb_msg_sanity_check(ldb, msg);
653
654
655         if (ret != LDB_SUCCESS) {
656                 return ret;
657         }
658
659         ret = ldb_build_add_req(&add_req, ldb, ac,
660                                 msg,
661                                 ac->req->controls,
662                                 ac, oc_op_callback,
663                                 ac->req);
664         if (ret != LDB_SUCCESS) {
665                 return ret;
666         }
667
668         /* perform the add */
669         return ldb_next_request(ac->module, add_req);
670 }
671
672 static int oc_modify_callback(struct ldb_request *req,
673                                 struct ldb_reply *ares);
674 static int objectclass_do_mod(struct oc_context *ac);
675
676 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
677 {
678         struct ldb_context *ldb = ldb_module_get_ctx(module);
679         struct ldb_message_element *objectclass_element;
680         struct ldb_message *msg;
681         struct ldb_request *down_req;
682         struct oc_context *ac;
683         bool oc_changes = false;
684         int ret;
685
686         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
687
688         /* do not manipulate our control entries */
689         if (ldb_dn_is_special(req->op.mod.message->dn)) {
690                 return ldb_next_request(module, req);
691         }
692
693         /* As with the "real" AD we don't accept empty messages */
694         if (req->op.mod.message->num_elements == 0) {
695                 ldb_set_errstring(ldb, "objectclass: modify message must have "
696                                        "elements/attributes!");
697                 return LDB_ERR_UNWILLING_TO_PERFORM;
698         }
699
700         ac = oc_init_context(module, req);
701         if (ac == NULL) {
702                 return LDB_ERR_OPERATIONS_ERROR;
703         }
704
705         /* Without schema, there isn't much to do here */
706         if (ac->schema == NULL) {
707                 talloc_free(ac);
708                 return ldb_next_request(module, req);
709         }
710
711         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
712         if (msg == NULL) {
713                 return LDB_ERR_OPERATIONS_ERROR;
714         }
715
716         /* For now change everything except the objectclasses */
717
718         objectclass_element = ldb_msg_find_element(msg, "objectClass");
719         if (objectclass_element != NULL) {
720                 ldb_msg_remove_attr(msg, "objectClass");
721                 oc_changes = true;
722         }
723
724         ret = ldb_build_mod_req(&down_req, ldb, ac,
725                                 msg,
726                                 req->controls, ac,
727                                 oc_changes ? oc_modify_callback : oc_op_callback,
728                                 req);
729         if (ret != LDB_SUCCESS) {
730                 return ret;
731         }
732
733         return ldb_next_request(module, down_req);
734 }
735
736 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
737 {
738         static const char * const attrs[] = { "objectClass", NULL };
739         struct ldb_context *ldb;
740         struct ldb_request *search_req;
741         struct oc_context *ac;
742         int ret;
743
744         ac = talloc_get_type(req->context, struct oc_context);
745         ldb = ldb_module_get_ctx(ac->module);
746
747         if (!ares) {
748                 return ldb_module_done(ac->req, NULL, NULL,
749                                         LDB_ERR_OPERATIONS_ERROR);
750         }
751
752         if (ares->type == LDB_REPLY_REFERRAL) {
753                 return ldb_module_send_referral(ac->req, ares->referral);
754         }
755
756         if (ares->error != LDB_SUCCESS) {
757                 return ldb_module_done(ac->req, ares->controls,
758                                         ares->response, ares->error);
759         }
760
761         if (ares->type != LDB_REPLY_DONE) {
762                 talloc_free(ares);
763                 return ldb_module_done(ac->req, NULL, NULL,
764                                         LDB_ERR_OPERATIONS_ERROR);
765         }
766
767         talloc_free(ares);
768
769         /* this looks up the real existing object for fetching some important
770          * informations (objectclasses) */
771         ret = ldb_build_search_req(&search_req, ldb,
772                                    ac, ac->req->op.mod.message->dn,
773                                    LDB_SCOPE_BASE,
774                                    "(objectClass=*)",
775                                    attrs, NULL, 
776                                    ac, get_search_callback,
777                                    ac->req);
778         if (ret != LDB_SUCCESS) {
779                 return ldb_module_done(ac->req, NULL, NULL, ret);
780         }
781
782         ac->step_fn = objectclass_do_mod;
783
784         ret = ldb_next_request(ac->module, search_req);
785         if (ret != LDB_SUCCESS) {
786                 return ldb_module_done(ac->req, NULL, NULL, ret);
787         }
788
789         return LDB_SUCCESS;
790 }
791
792 static int objectclass_do_mod(struct oc_context *ac)
793 {
794         struct ldb_context *ldb;
795         struct ldb_request *mod_req;
796         char *value;
797         struct ldb_message_element *oc_el_entry, *oc_el_change;
798         struct ldb_val *vals;
799         struct ldb_message *msg;
800         TALLOC_CTX *mem_ctx;
801         struct class_list *sorted, *current;
802         const struct dsdb_class *objectclass;
803         unsigned int i, j;
804         bool found, replace = false;
805         int ret;
806
807         ldb = ldb_module_get_ctx(ac->module);
808
809         /* we should always have a valid entry when we enter here */
810         if (ac->search_res == NULL) {
811                 return LDB_ERR_OPERATIONS_ERROR;
812         }
813
814         oc_el_entry = ldb_msg_find_element(ac->search_res->message,
815                                            "objectClass");
816         if (oc_el_entry == NULL) {
817                 /* existing entry without a valid object class? */
818                 return LDB_ERR_OPERATIONS_ERROR;
819         }
820
821         oc_el_change = ldb_msg_find_element(ac->req->op.mod.message,
822                                             "objectClass");
823         if (oc_el_change == NULL) {
824                 /* we should have an objectclass change operation */
825                 return LDB_ERR_OPERATIONS_ERROR;
826         }
827
828         /* use a new message structure */
829         msg = ldb_msg_new(ac);
830         if (msg == NULL) {
831                 ldb_oom(ldb);
832                 return LDB_ERR_OPERATIONS_ERROR;
833         }
834
835         msg->dn = ac->req->op.mod.message->dn;
836
837         mem_ctx = talloc_new(ac);
838         if (mem_ctx == NULL) {
839                 ldb_oom(ldb);
840                 return LDB_ERR_OPERATIONS_ERROR;
841         }
842
843         switch (oc_el_change->flags & LDB_FLAG_MOD_MASK) {
844         case LDB_FLAG_MOD_ADD:
845                 /* Merge the two message elements */
846                 for (i = 0; i < oc_el_change->num_values; i++) {
847                         for (j = 0; j < oc_el_entry->num_values; j++) {
848                                 if (strcasecmp((char *)oc_el_change->values[i].data,
849                                                (char *)oc_el_entry->values[j].data) == 0) {
850                                         /* we cannot add an already existing object class */
851                                         talloc_free(mem_ctx);
852                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
853                                 }
854                         }
855                         /* append the new object class value - code was copied
856                          * from "ldb_msg_add_value" */
857                         vals = talloc_realloc(oc_el_entry, oc_el_entry->values,
858                                               struct ldb_val,
859                                               oc_el_entry->num_values + 1);
860                         if (vals == NULL) {
861                                 ldb_oom(ldb);
862                                 talloc_free(mem_ctx);
863                                 return LDB_ERR_OPERATIONS_ERROR;
864                         }
865                         oc_el_entry->values = vals;
866                         oc_el_entry->values[oc_el_entry->num_values] =
867                                 oc_el_change->values[i];
868                         ++(oc_el_entry->num_values);
869                 }
870
871                 objectclass = get_last_structural_class(ac->schema,
872                                                         oc_el_change);
873                 if (objectclass != NULL) {
874                         /* we cannot add a new structural object class */
875                         talloc_free(mem_ctx);
876                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
877                 }
878
879                 /* Now do the sorting */
880                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
881                                        oc_el_entry, &sorted);
882                 if (ret != LDB_SUCCESS) {
883                         talloc_free(mem_ctx);
884                         return ret;
885                 }
886
887                 break;
888
889         case LDB_FLAG_MOD_REPLACE:
890                 /* Do the sorting for the change message element */
891                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
892                                        oc_el_change, &sorted);
893                 if (ret != LDB_SUCCESS) {
894                         talloc_free(mem_ctx);
895                         return ret;
896                 }
897
898                 /* this is a replace */
899                 replace = true;
900
901                 break;
902
903         case LDB_FLAG_MOD_DELETE:
904                 /* get the actual top-most structural objectclass */
905                 objectclass = get_last_structural_class(ac->schema,
906                                                         oc_el_entry);
907                 if (objectclass == NULL) {
908                         talloc_free(mem_ctx);
909                         return LDB_ERR_OPERATIONS_ERROR;
910                 }
911
912                 /* Merge the two message elements */
913                 for (i = 0; i < oc_el_change->num_values; i++) {
914                         found = false;
915                         for (j = 0; j < oc_el_entry->num_values; j++) {
916                                 if (strcasecmp((char *)oc_el_change->values[i].data,
917                                                (char *)oc_el_entry->values[j].data) == 0) {
918                                         found = true;
919                                         /* delete the object class value -
920                                          * code was copied from
921                                          * "ldb_msg_remove_element" */
922                                         if (j != oc_el_entry->num_values - 1) {
923                                                 memmove(&oc_el_entry->values[j],
924                                                         &oc_el_entry->values[j+1],
925                                                         ((oc_el_entry->num_values-1) - j)*sizeof(struct ldb_val));
926                                         }
927                                         --(oc_el_entry->num_values);
928                                         break;
929                                 }
930                         }
931                         if (!found) {
932                                 /* we cannot delete a not existing object class */
933                                 talloc_free(mem_ctx);
934                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
935                         }
936                 }
937
938                 /* Make sure that the top-most structural objectclass wasn't
939                  * deleted */
940                 found = false;
941                 for (i = 0; i < oc_el_entry->num_values; i++) {
942                         if (strcasecmp(objectclass->lDAPDisplayName,
943                             (char *)oc_el_entry->values[i].data) == 0) {
944                                 found = true; break;
945                         }
946                 }
947                 if (!found) {
948                         talloc_free(mem_ctx);
949                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
950                 }
951
952
953                 /* Now do the sorting */
954                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
955                                        oc_el_entry, &sorted);
956                 if (ret != LDB_SUCCESS) {
957                         talloc_free(mem_ctx);
958                         return ret;
959                 }
960
961                 break;
962         }
963
964         ret = ldb_msg_add_empty(msg, "objectClass",
965                                 LDB_FLAG_MOD_REPLACE, &oc_el_change);
966         if (ret != LDB_SUCCESS) {
967                 ldb_oom(ldb);
968                 talloc_free(mem_ctx);
969                 return ret;
970         }
971
972         /* Move from the linked list back into an ldb msg */
973         for (current = sorted; current; current = current->next) {
974                 value = talloc_strdup(msg,
975                                       current->objectclass->lDAPDisplayName);
976                 if (value == NULL) {
977                         ldb_oom(ldb);
978                         talloc_free(mem_ctx);
979                         return LDB_ERR_OPERATIONS_ERROR;
980                 }
981                 ret = ldb_msg_add_string(msg, "objectClass", value);
982                 if (ret != LDB_SUCCESS) {
983                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
984                         talloc_free(mem_ctx);
985                         return ret;
986                 }
987         }
988
989         talloc_free(mem_ctx);
990
991         if (replace) {
992                 /* Well, on replace we are nearly done: we have to test if
993                  * the change and entry message element are identically. We
994                  * can use "ldb_msg_element_compare" since now the specified
995                  * objectclasses match for sure in case. */
996                 ret = ldb_msg_element_compare(oc_el_entry, oc_el_change);
997                 if (ret == 0) {
998                         ret = ldb_msg_element_compare(oc_el_change,
999                                                       oc_el_entry);
1000                 }
1001                 if (ret == 0) {
1002                         /* they are the same so we are done in this case */
1003                         return ldb_module_done(ac->req, NULL, NULL,
1004                                                LDB_SUCCESS);
1005                 } else {
1006                         /* they're not exactly the same */
1007                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1008                 }
1009         }
1010
1011         /* in the other cases we have the real change left to do */
1012
1013         ret = ldb_msg_sanity_check(ldb, msg);
1014         if (ret != LDB_SUCCESS) {
1015                 return ret;
1016         }
1017
1018         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1019                                 msg,
1020                                 ac->req->controls,
1021                                 ac, oc_op_callback,
1022                                 ac->req);
1023         if (ret != LDB_SUCCESS) {
1024                 return ret;
1025         }
1026
1027         return ldb_next_request(ac->module, mod_req);
1028 }
1029
1030 static int objectclass_do_rename(struct oc_context *ac);
1031
1032 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1033 {
1034         static const char * const attrs[] = { "objectClass", NULL };
1035         struct ldb_context *ldb;
1036         struct ldb_request *search_req;
1037         struct oc_context *ac;
1038         struct ldb_dn *parent_dn;
1039         int ret;
1040
1041         ldb = ldb_module_get_ctx(module);
1042
1043         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1044
1045         /* do not manipulate our control entries */
1046         if (ldb_dn_is_special(req->op.rename.newdn)) {
1047                 return ldb_next_request(module, req);
1048         }
1049
1050         ac = oc_init_context(module, req);
1051         if (ac == NULL) {
1052                 return LDB_ERR_OPERATIONS_ERROR;
1053         }
1054
1055         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1056         if (parent_dn == NULL) {
1057                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, the parent DN does not exist!",
1058                                        ldb_dn_get_linearized(req->op.rename.olddn));
1059                 return LDB_ERR_NO_SUCH_OBJECT;
1060         }
1061
1062         /* this looks up the parent object for fetching some important
1063          * informations (objectclasses, DN normalisation...) */
1064         ret = ldb_build_search_req(&search_req, ldb,
1065                                    ac, parent_dn, LDB_SCOPE_BASE,
1066                                    "(objectClass=*)",
1067                                    attrs, NULL,
1068                                    ac, get_search_callback,
1069                                    req);
1070         if (ret != LDB_SUCCESS) {
1071                 return ret;
1072         }
1073
1074         /* we have to add the show deleted control, as otherwise DRS
1075            deletes will be refused as we will think the target parent
1076            does not exist */
1077         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1078
1079         if (ret != LDB_SUCCESS) {
1080                 return ret;
1081         }
1082
1083         ac->step_fn = objectclass_do_rename;
1084
1085         return ldb_next_request(ac->module, search_req);
1086 }
1087
1088 static int objectclass_do_rename2(struct oc_context *ac);
1089
1090 static int objectclass_do_rename(struct oc_context *ac)
1091 {
1092         static const char * const attrs[] = { "objectClass", NULL };
1093         struct ldb_context *ldb;
1094         struct ldb_request *search_req;
1095         int ret;
1096
1097         ldb = ldb_module_get_ctx(ac->module);
1098
1099         /* Check if we have a valid parent - this check is needed since
1100          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1101         if (ac->search_res == NULL) {
1102                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1103                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1104                 return LDB_ERR_OTHER;
1105         }
1106
1107         /* now assign "search_res2" to the parent entry to have "search_res"
1108          * free for another lookup */
1109         ac->search_res2 = ac->search_res;
1110         ac->search_res = NULL;
1111
1112         /* this looks up the real existing object for fetching some important
1113          * informations (objectclasses) */
1114         ret = ldb_build_search_req(&search_req, ldb,
1115                                    ac, ac->req->op.rename.olddn,
1116                                    LDB_SCOPE_BASE,
1117                                    "(objectClass=*)",
1118                                    attrs, NULL,
1119                                    ac, get_search_callback,
1120                                    ac->req);
1121         if (ret != LDB_SUCCESS) {
1122                 return ret;
1123         }
1124
1125         ac->step_fn = objectclass_do_rename2;
1126
1127         return ldb_next_request(ac->module, search_req);
1128 }
1129
1130 static int objectclass_do_rename2(struct oc_context *ac)
1131 {
1132         struct ldb_context *ldb;
1133         struct ldb_request *rename_req;
1134         struct ldb_dn *fixed_dn;
1135         int ret;
1136
1137         ldb = ldb_module_get_ctx(ac->module);
1138
1139         /* Check if we have a valid entry - this check is needed since
1140          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1141         if (ac->search_res == NULL) {
1142                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1143                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1144                 return LDB_ERR_NO_SUCH_OBJECT;
1145         }
1146
1147         if (ac->schema != NULL) {
1148                 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1149                 const struct dsdb_class *objectclass;
1150                 const char *rdn_name;
1151                 bool allowed_class = false;
1152                 unsigned int i, j;
1153
1154                 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1155                                                    "objectClass");
1156                 if (oc_el_entry == NULL) {
1157                         /* existing entry without a valid object class? */
1158                         return LDB_ERR_OPERATIONS_ERROR;
1159                 }
1160                 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1161                 if (objectclass == NULL) {
1162                         /* existing entry without a valid object class? */
1163                         return LDB_ERR_OPERATIONS_ERROR;
1164                 }
1165
1166                 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1167                 if ((objectclass->rDNAttID != NULL) &&
1168                     (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1169                         ldb_asprintf_errstring(ldb,
1170                                                "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1171                                                rdn_name,
1172                                                objectclass->lDAPDisplayName,
1173                                                objectclass->rDNAttID);
1174                         return LDB_ERR_UNWILLING_TO_PERFORM;
1175                 }
1176
1177                 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1178                                                     "objectClass");
1179                 if (oc_el_parent == NULL) {
1180                         /* existing entry without a valid object class? */
1181                         return LDB_ERR_OPERATIONS_ERROR;
1182                 }
1183
1184                 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1185                         const struct dsdb_class *sclass;
1186
1187                         sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1188                                                                        &oc_el_parent->values[i]);
1189                         if (!sclass) {
1190                                 /* We don't know this class?  what is going on? */
1191                                 continue;
1192                         }
1193                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1194                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1195                                         allowed_class = true;
1196                                         break;
1197                                 }
1198                         }
1199                 }
1200
1201                 if (!allowed_class) {
1202                         ldb_asprintf_errstring(ldb,
1203                                                "objectclass: structural objectClass %s is not a valid child class for %s",
1204                                                objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1205                         return LDB_ERR_NAMING_VIOLATION;
1206                 }
1207         }
1208
1209         /* Ensure we are not trying to rename it to be a child of itself */
1210         if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1211                                  ac->req->op.rename.newdn) == 0)  &&
1212             (ldb_dn_compare(ac->req->op.rename.olddn,
1213                             ac->req->op.rename.newdn) != 0)) {
1214                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1215                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1216                 return LDB_ERR_UNWILLING_TO_PERFORM;
1217         }
1218
1219         /* Fix up the DN to be in the standard form, taking
1220          * particular care to match the parent DN */
1221         ret = fix_dn(ac,
1222                      ac->req->op.rename.newdn,
1223                      ac->search_res2->message->dn,
1224                      &fixed_dn);
1225         if (ret != LDB_SUCCESS) {
1226                 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1227                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1228                 return ret;
1229
1230         }
1231
1232         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1233                                    ac->req->op.rename.olddn, fixed_dn,
1234                                    ac->req->controls,
1235                                    ac, oc_op_callback,
1236                                    ac->req);
1237         if (ret != LDB_SUCCESS) {
1238                 return ret;
1239         }
1240
1241         /* perform the rename */
1242         return ldb_next_request(ac->module, rename_req);
1243 }
1244
1245 static int objectclass_do_delete(struct oc_context *ac);
1246
1247 static int objectclass_delete(struct ldb_module *module, struct ldb_request *req)
1248 {
1249         static const char * const attrs[] = { "systemFlags", NULL };
1250         struct ldb_context *ldb;
1251         struct ldb_request *search_req;
1252         struct oc_context *ac;
1253         int ret;
1254
1255         ldb = ldb_module_get_ctx(module);
1256
1257         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_delete\n");
1258
1259         /* do not manipulate our control entries */
1260         if (ldb_dn_is_special(req->op.del.dn)) {
1261                 return ldb_next_request(module, req);
1262         }
1263
1264         /* Bypass the "systemFlags" checks when we do have the "RELAX" control
1265          * set. */
1266         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) != NULL) {
1267                 return ldb_next_request(module, req);
1268         }
1269
1270         ac = oc_init_context(module, req);
1271         if (ac == NULL) {
1272                 return LDB_ERR_OPERATIONS_ERROR;
1273         }
1274
1275         /* this looks up the entry object for fetching some important
1276          * informations (systemFlags...) */
1277         ret = ldb_build_search_req(&search_req, ldb,
1278                                    ac, req->op.del.dn, LDB_SCOPE_BASE,
1279                                    "(objectClass=*)",
1280                                    attrs, NULL,
1281                                    ac, get_search_callback,
1282                                    req);
1283         if (ret != LDB_SUCCESS) {
1284                 return ret;
1285         }
1286
1287         ac->step_fn = objectclass_do_delete;
1288
1289         return ldb_next_request(ac->module, search_req);
1290 }
1291
1292 static int objectclass_do_delete(struct oc_context *ac)
1293 {
1294         struct ldb_context *ldb;
1295         int32_t systemFlags;
1296
1297         ldb = ldb_module_get_ctx(ac->module);
1298
1299         /* Check if we have a valid entry - this check is needed since
1300          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1301         if (ac->search_res == NULL) {
1302                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, entry does not exist!",
1303                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1304                 return LDB_ERR_NO_SUCH_OBJECT;
1305         }
1306
1307         systemFlags = ldb_msg_find_attr_as_int(ac->search_res->message,
1308                                                "systemFlags", 0);
1309         if ((systemFlags & SYSTEM_FLAG_DISALLOW_DELETE) != 0) {
1310                 ldb_asprintf_errstring(ldb, "objectclass: Cannot delete %s, it isn't permitted!",
1311                                        ldb_dn_get_linearized(ac->req->op.del.dn));
1312                 return LDB_ERR_UNWILLING_TO_PERFORM;
1313         }
1314
1315         return ldb_next_request(ac->module, ac->req);
1316 }
1317
1318 static int objectclass_init(struct ldb_module *module)
1319 {
1320         struct ldb_context *ldb = ldb_module_get_ctx(module);
1321         int ret;
1322
1323         /* Init everything else */
1324         ret = ldb_next_init(module);
1325         if (ret != LDB_SUCCESS) {
1326                 return ret;
1327         }
1328         
1329         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1330         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1331
1332         return ret;
1333 }
1334
1335 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1336         .name           = "objectclass",
1337         .add            = objectclass_add,
1338         .modify         = objectclass_modify,
1339         .rename         = objectclass_rename,
1340         .del            = objectclass_delete,
1341         .init_context   = objectclass_init
1342 };