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