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