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