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