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