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