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