s4:objectclass LDB module - remove "fix_check_attributes"
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2006-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6    Copyright (C) Matthias Dieter Wallnöfer 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  *  Name: ldb
24  *
25  *  Component: objectClass sorting and constraint checking module
26  *
27  *  Description: 
28  *  - sort the objectClass attribute into the class
29  *    hierarchy and perform constraint checks (correct RDN name,
30  *    valid parent),
31  *  - fix DNs into 'standard' case
32  *  - Add objectCategory and some other attribute defaults
33  *
34  *  Author: Andrew Bartlett
35  */
36
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "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 "util.h"
49
50 struct oc_context {
51
52         struct ldb_module *module;
53         struct ldb_request *req;
54         const struct dsdb_schema *schema;
55
56         struct ldb_reply *search_res;
57         struct ldb_reply *search_res2;
58
59         int (*step_fn)(struct oc_context *);
60 };
61
62 struct class_list {
63         struct class_list *prev, *next;
64         const struct dsdb_class *objectclass;
65 };
66
67 static struct oc_context *oc_init_context(struct ldb_module *module,
68                                           struct ldb_request *req)
69 {
70         struct ldb_context *ldb;
71         struct oc_context *ac;
72
73         ldb = ldb_module_get_ctx(module);
74
75         ac = talloc_zero(req, struct oc_context);
76         if (ac == NULL) {
77                 ldb_oom(ldb);
78                 return NULL;
79         }
80
81         ac->module = module;
82         ac->req = req;
83         ac->schema = dsdb_get_schema(ldb, ac);
84
85         return ac;
86 }
87
88 static int objectclass_do_add(struct oc_context *ac);
89
90 /* Sort objectClasses into correct order, and validate that all
91  * objectClasses specified actually exist in the schema
92  */
93
94 static int objectclass_sort(struct ldb_module *module,
95                             const struct dsdb_schema *schema,
96                             TALLOC_CTX *mem_ctx,
97                             struct ldb_message_element *objectclass_element,
98                             struct class_list **sorted_out) 
99 {
100         struct ldb_context *ldb;
101         unsigned int i, lowest;
102         struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
103
104         ldb = ldb_module_get_ctx(module);
105
106         /* DESIGN:
107          *
108          * We work on 4 different 'bins' (implemented here as linked lists):
109          *
110          * * sorted:       the eventual list, in the order we wish to push
111          *                 into the database.  This is the only ordered list.
112          *
113          * * parent_class: The current parent class 'bin' we are
114          *                 trying to find subclasses for
115          *
116          * * subclass:     The subclasses we have found so far
117          *
118          * * unsorted:     The remaining objectClasses
119          *
120          * The process is a matter of filtering objectClasses up from
121          * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
122          * 
123          * We start with 'top' (found and promoted to parent_class
124          * initially).  Then we find (in unsorted) all the direct
125          * subclasses of 'top'.  parent_classes is concatenated onto
126          * the end of 'sorted', and subclass becomes the list in
127          * parent_class.
128          *
129          * We then repeat, until we find no more subclasses.  Any left
130          * over classes are added to the end.
131          *
132          */
133
134         /* Firstly, dump all the objectClass elements into the
135          * unsorted bin, except for 'top', which is special */
136         for (i=0; i < objectclass_element->num_values; i++) {
137                 current = talloc(mem_ctx, struct class_list);
138                 if (!current) {
139                         ldb_oom(ldb);
140                         return LDB_ERR_OPERATIONS_ERROR;
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(TALLOC_CTX *mem_ctx, 
315                   struct ldb_dn *newdn, struct ldb_dn *parent_dn, 
316                   struct ldb_dn **fixed_dn) 
317 {
318         char *upper_rdn_attr;
319         const struct ldb_val *rdn_val;
320
321         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
322         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
323
324         /* We need the attribute name in upper case */
325         upper_rdn_attr = strupper_talloc(*fixed_dn, 
326                                          ldb_dn_get_rdn_name(newdn));
327         if (!upper_rdn_attr) {
328                 return LDB_ERR_OPERATIONS_ERROR;
329         }
330
331         /* Create a new child */
332         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
333                 return LDB_ERR_OPERATIONS_ERROR;
334         }
335
336
337         rdn_val = ldb_dn_get_rdn_val(newdn);
338
339 #if 0
340         /* the rules for rDN length constraints are more complex than
341         this. Until we understand them we need to leave this
342         constraint out. Otherwise we break replication, as windows
343         does sometimes send us rDNs longer than 64 */
344         if (!rdn_val || rdn_val->length > 64) {
345                 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
346         }
347 #endif
348
349
350         /* And replace it with CN=foo (we need the attribute in upper case */
351         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
352 }
353
354
355 static int objectclass_do_add(struct oc_context *ac);
356
357 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
358 {
359         struct ldb_context *ldb;
360         struct ldb_request *search_req;
361         struct oc_context *ac;
362         struct ldb_dn *parent_dn;
363         int ret;
364         static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
365
366         ldb = ldb_module_get_ctx(module);
367
368         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
369
370         /* do not manipulate our control entries */
371         if (ldb_dn_is_special(req->op.add.message->dn)) {
372                 return ldb_next_request(module, req);
373         }
374
375         /* the objectClass must be specified on add */
376         if (ldb_msg_find_element(req->op.add.message, 
377                                  "objectClass") == NULL) {
378                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
379         }
380
381         ac = oc_init_context(module, req);
382         if (ac == NULL) {
383                 return LDB_ERR_OPERATIONS_ERROR;
384         }
385
386         /* If there isn't a parent, just go on to the add processing */
387         if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
388                 return objectclass_do_add(ac);
389         }
390
391         /* get copy of parent DN */
392         parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
393         if (parent_dn == NULL) {
394                 ldb_oom(ldb);
395                 return LDB_ERR_OPERATIONS_ERROR;
396         }
397
398         ret = ldb_build_search_req(&search_req, ldb,
399                                    ac, parent_dn, LDB_SCOPE_BASE,
400                                    "(objectClass=*)", parent_attrs,
401                                    NULL,
402                                    ac, get_search_callback,
403                                    req);
404         if (ret != LDB_SUCCESS) {
405                 return ret;
406         }
407
408         ac->step_fn = objectclass_do_add;
409
410         return ldb_next_request(ac->module, search_req);
411 }
412
413 static int objectclass_do_add(struct oc_context *ac)
414 {
415         struct ldb_context *ldb;
416         struct ldb_request *add_req;
417         char *value;
418         struct ldb_message_element *objectclass_element, *el;
419         struct ldb_message *msg;
420         TALLOC_CTX *mem_ctx;
421         struct class_list *sorted, *current;
422         int ret;
423         const struct dsdb_class *objectclass;
424         int32_t systemFlags = 0;
425         const char *rdn_name = NULL;
426
427         ldb = ldb_module_get_ctx(ac->module);
428
429         mem_ctx = talloc_new(ac);
430         if (mem_ctx == NULL) {
431                 ldb_oom(ldb);
432                 return LDB_ERR_OPERATIONS_ERROR;
433         }
434
435         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
436
437         /* Check if we have a valid parent - this check is needed since
438          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
439         if (ac->search_res == NULL) {
440                 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
441                         /* Allow the tree to be started */
442                         
443                         /* but don't keep any error string, it's meaningless */
444                         ldb_set_errstring(ldb, NULL);
445                 } else {
446                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
447                                                ldb_dn_get_linearized(msg->dn));
448                         talloc_free(mem_ctx);
449                         return LDB_ERR_NO_SUCH_OBJECT;
450                 }
451         } else {
452
453                 /* Fix up the DN to be in the standard form, taking
454                  * particular care to match the parent DN */
455                 ret = fix_dn(msg, 
456                              ac->req->op.add.message->dn,
457                              ac->search_res->message->dn,
458                              &msg->dn);
459
460                 if (ret != LDB_SUCCESS) {
461                         ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
462                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
463                         talloc_free(mem_ctx);
464                         return ret;
465                 }
466
467         }
468         if (ac->schema != NULL) {
469                 /* This is now the objectClass list from the database */
470                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
471
472                 if (!objectclass_element) {
473                         /* Where did it go?  bail now... */
474                         talloc_free(mem_ctx);
475                         return LDB_ERR_OPERATIONS_ERROR;
476                 }
477                 ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
478                                        objectclass_element, &sorted);
479                 if (ret != LDB_SUCCESS) {
480                         talloc_free(mem_ctx);
481                         return ret;
482                 }
483                 
484                 ldb_msg_remove_attr(msg, "objectClass");
485                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
486                 
487                 if (ret != LDB_SUCCESS) {
488                         talloc_free(mem_ctx);
489                         return ret;
490                 }
491
492                 /* We must completely replace the existing objectClass entry,
493                  * because we need it sorted */
494
495                 /* Move from the linked list back into an ldb msg */
496                 for (current = sorted; current; current = current->next) {
497                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
498                         if (value == NULL) {
499                                 ldb_oom(ldb);
500                                 talloc_free(mem_ctx);
501                                 return LDB_ERR_OPERATIONS_ERROR;
502                         }
503                         ret = ldb_msg_add_string(msg, "objectClass", value);
504                         if (ret != LDB_SUCCESS) {
505                                 ldb_set_errstring(ldb,
506                                                   "objectclass: could not re-add sorted "
507                                                   "objectclass to modify msg");
508                                 talloc_free(mem_ctx);
509                                 return ret;
510                         }
511                 }
512
513                 /* Retrive the message again so get_last_structural_class works */
514                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
515
516                 /* Make sure its valid to add an object of this type */
517                 objectclass = get_last_structural_class(ac->schema,
518                                                         objectclass_element);
519                 if(objectclass == NULL) {
520                         ldb_asprintf_errstring(ldb,
521                                                "Failed to find a structural class for %s",
522                                                ldb_dn_get_linearized(msg->dn));
523                         return LDB_ERR_UNWILLING_TO_PERFORM;
524                 }
525
526                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
527                 if (objectclass->rDNAttID
528                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
529                         ldb_asprintf_errstring(ldb,
530                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
531                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
532                         return LDB_ERR_NAMING_VIOLATION;
533                 }
534
535                 if (ac->search_res && ac->search_res->message) {
536                         struct ldb_message_element *oc_el
537                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
538
539                         bool allowed_class = false;
540                         unsigned int i, j;
541                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
542                                 const struct dsdb_class *sclass;
543
544                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
545                                                                                &oc_el->values[i]);
546                                 if (!sclass) {
547                                         /* We don't know this class?  what is going on? */
548                                         continue;
549                                 }
550                                 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
551                                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
552                                                 allowed_class = true;
553                                                 break;
554                                         }
555                                 }
556                         }
557
558                         if (!allowed_class) {
559                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
560                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
561                                 return LDB_ERR_NAMING_VIOLATION;
562                         }
563                 }
564
565                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
566                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
567                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
568                         return LDB_ERR_UNWILLING_TO_PERFORM;
569                 }
570
571                 if (!ldb_msg_find_element(msg, "objectCategory")) {
572                         struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
573                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
574                                 /* Strip off extended components */
575                                 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
576                                 value = ldb_dn_alloc_linearized(msg, dn);
577                                 talloc_free(dn);
578                         } else {
579                                 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
580                         }
581                         if (value == NULL) {
582                                 ldb_oom(ldb);
583                                 talloc_free(mem_ctx);
584                                 return LDB_ERR_OPERATIONS_ERROR;
585                         }
586                         ldb_msg_add_string(msg, "objectCategory", value);
587                 }
588                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
589                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
590                                                 "TRUE");
591                 }
592
593                 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
594                 el = ldb_msg_find_element(msg, "systemFlags");
595
596                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
597
598                 if (el) {
599                         /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
600                         /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
601                         ldb_msg_remove_element(msg, el);
602                 }
603
604                 /* This flag is only allowed on attributeSchema objects */
605                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
606                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
607                 }
608
609                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
610                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
611                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
612                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
613                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
614                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
615
616                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
617                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
618                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
619                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
620                 }
621
622                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
623
624                 if (el || systemFlags != 0) {
625                         samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
626                 }
627         }
628
629         talloc_free(mem_ctx);
630         ret = ldb_msg_sanity_check(ldb, msg);
631
632
633         if (ret != LDB_SUCCESS) {
634                 return ret;
635         }
636
637         ret = ldb_build_add_req(&add_req, ldb, ac,
638                                 msg,
639                                 ac->req->controls,
640                                 ac, oc_op_callback,
641                                 ac->req);
642         if (ret != LDB_SUCCESS) {
643                 return ret;
644         }
645
646         /* perform the add */
647         return ldb_next_request(ac->module, add_req);
648 }
649
650 static int oc_modify_callback(struct ldb_request *req,
651                                 struct ldb_reply *ares);
652 static int objectclass_do_mod(struct oc_context *ac);
653
654 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
655 {
656         struct ldb_context *ldb = ldb_module_get_ctx(module);
657         struct ldb_message_element *objectclass_element;
658         struct ldb_message *msg;
659         struct class_list *sorted, *current;
660         struct ldb_request *down_req;
661         struct oc_context *ac;
662         TALLOC_CTX *mem_ctx;
663         char *value;
664         int ret;
665
666         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
667
668         /* do not manipulate our control entries */
669         if (ldb_dn_is_special(req->op.mod.message->dn)) {
670                 return ldb_next_request(module, req);
671         }
672
673         /* As with the "real" AD we don't accept empty messages */
674         if (req->op.mod.message->num_elements == 0) {
675                 ldb_set_errstring(ldb, "objectclass: modify message must have "
676                                        "elements/attributes!");
677                 return LDB_ERR_UNWILLING_TO_PERFORM;
678         }
679
680         ac = oc_init_context(module, req);
681         if (ac == NULL) {
682                 return LDB_ERR_OPERATIONS_ERROR;
683         }
684
685         if (ac->schema == NULL) {
686                 /* Without schema, there isn't much to do here */
687                 talloc_free(ac);
688                 return ldb_next_request(module, req);
689         }
690
691         /* If no part of this touches the objectClass, then we don't
692          * need to make any changes.  */
693         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
694
695         /* If the only operation is the deletion of the objectClass
696          * then go on with just fixing the attribute case */
697         if (!objectclass_element) {
698                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
699                 if (msg == NULL) {
700                         return LDB_ERR_OPERATIONS_ERROR;
701                 }
702                 
703                 ret = ldb_build_mod_req(&down_req, ldb, ac,
704                                         msg,
705                                         req->controls,
706                                         ac, oc_op_callback,
707                                         req);
708                 if (ret != LDB_SUCCESS) {
709                         return ret;
710                 }
711
712                 /* go on with the call chain */
713                 return ldb_next_request(module, down_req);
714         }
715
716         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
717         case LDB_FLAG_MOD_DELETE:
718                 if (objectclass_element->num_values == 0) {
719                         return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
720                 }
721                 break;
722
723         case LDB_FLAG_MOD_REPLACE:
724                 mem_ctx = talloc_new(ac);
725                 if (mem_ctx == NULL) {
726                         return LDB_ERR_OPERATIONS_ERROR;
727                 }
728
729                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
730                 if (msg == NULL) {
731                         talloc_free(mem_ctx);
732                         return LDB_ERR_OPERATIONS_ERROR;
733                 }
734
735                 ret = objectclass_sort(module, ac->schema, mem_ctx,
736                                        objectclass_element, &sorted);
737                 if (ret != LDB_SUCCESS) {
738                         talloc_free(mem_ctx);
739                         return ret;
740                 }
741
742                 /* We must completely replace the existing objectClass entry,
743                  * because we need it sorted */
744                 
745                 ldb_msg_remove_attr(msg, "objectClass");
746                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
747                 
748                 if (ret != LDB_SUCCESS) {
749                         talloc_free(mem_ctx);
750                         return ret;
751                 }
752
753                 /* Move from the linked list back into an ldb msg */
754                 for (current = sorted; current; current = current->next) {
755                         /* copy the value as this string is on the schema
756                          * context and we can't rely on it not changing
757                          * before the operation is over */
758                         value = talloc_strdup(msg,
759                                         current->objectclass->lDAPDisplayName);
760                         if (value == NULL) {
761                                 ldb_oom(ldb);
762                                 talloc_free(mem_ctx);
763                                 return LDB_ERR_OPERATIONS_ERROR;
764                         }
765                         ret = ldb_msg_add_string(msg, "objectClass", value);
766                         if (ret != LDB_SUCCESS) {
767                                 ldb_set_errstring(ldb,
768                                         "objectclass: could not re-add sorted "
769                                         "objectclass to modify msg");
770                                 talloc_free(mem_ctx);
771                                 return ret;
772                         }
773                 }
774                 
775                 talloc_free(mem_ctx);
776
777                 ret = ldb_msg_sanity_check(ldb, msg);
778                 if (ret != LDB_SUCCESS) {
779                         return ret;
780                 }
781
782                 ret = ldb_build_mod_req(&down_req, ldb, ac,
783                                         msg,
784                                         req->controls,
785                                         ac, oc_op_callback,
786                                         req);
787                 if (ret != LDB_SUCCESS) {
788                         return ret;
789                 }
790
791                 /* go on with the call chain */
792                 return ldb_next_request(module, down_req);
793         }
794
795         /* This isn't the default branch of the switch, but a 'in any
796          * other case'.  When a delete isn't for all objectClasses for
797          * example
798          */
799
800         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
801         if (msg == NULL) {
802                 ldb_oom(ldb);
803                 return LDB_ERR_OPERATIONS_ERROR;
804         }
805
806         ret = ldb_build_mod_req(&down_req, ldb, ac,
807                                 msg,
808                                 req->controls,
809                                 ac, oc_modify_callback,
810                                 req);
811         if (ret != LDB_SUCCESS) {
812                 return ret;
813         }
814
815         return ldb_next_request(module, down_req);
816 }
817
818 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
819 {
820         struct ldb_context *ldb;
821         static const char * const attrs[] = { "objectClass", NULL };
822         struct ldb_request *search_req;
823         struct oc_context *ac;
824         int ret;
825
826         ac = talloc_get_type(req->context, struct oc_context);
827         ldb = ldb_module_get_ctx(ac->module);
828
829         if (!ares) {
830                 return ldb_module_done(ac->req, NULL, NULL,
831                                         LDB_ERR_OPERATIONS_ERROR);
832         }
833
834         if (ares->type == LDB_REPLY_REFERRAL) {
835                 return ldb_module_send_referral(ac->req, ares->referral);
836         }
837
838         if (ares->error != LDB_SUCCESS) {
839                 return ldb_module_done(ac->req, ares->controls,
840                                         ares->response, ares->error);
841         }
842
843         if (ares->type != LDB_REPLY_DONE) {
844                 talloc_free(ares);
845                 return ldb_module_done(ac->req, NULL, NULL,
846                                         LDB_ERR_OPERATIONS_ERROR);
847         }
848
849         talloc_free(ares);
850
851         ret = ldb_build_search_req(&search_req, ldb, ac,
852                                    ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
853                                    "(objectClass=*)",
854                                    attrs, NULL, 
855                                    ac, get_search_callback,
856                                    ac->req);
857         if (ret != LDB_SUCCESS) {
858                 return ldb_module_done(ac->req, NULL, NULL, ret);
859         }
860
861         ac->step_fn = objectclass_do_mod;
862
863         ret = ldb_next_request(ac->module, search_req);
864         if (ret != LDB_SUCCESS) {
865                 return ldb_module_done(ac->req, NULL, NULL, ret);
866         }
867         return LDB_SUCCESS;
868 }
869
870 static int objectclass_do_mod(struct oc_context *ac)
871 {
872         struct ldb_context *ldb;
873         struct ldb_request *mod_req;
874         char *value;
875         struct ldb_message_element *objectclass_element;
876         struct ldb_message *msg;
877         TALLOC_CTX *mem_ctx;
878         struct class_list *sorted, *current;
879         int ret;
880
881         ldb = ldb_module_get_ctx(ac->module);
882
883         if (ac->search_res == NULL) {
884                 return LDB_ERR_OPERATIONS_ERROR;
885         }
886
887         mem_ctx = talloc_new(ac);
888         if (mem_ctx == NULL) {
889                 return LDB_ERR_OPERATIONS_ERROR;
890         }
891
892         /* use a new message structure */
893         msg = ldb_msg_new(ac);
894         if (msg == NULL) {
895                 ldb_set_errstring(ldb,
896                         "objectclass: could not create new modify msg");
897                 talloc_free(mem_ctx);
898                 return LDB_ERR_OPERATIONS_ERROR;
899         }
900
901         /* This is now the objectClass list from the database */
902         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
903                                                    "objectClass");
904         if (!objectclass_element) {
905                 /* Where did it go?  bail now... */
906                 talloc_free(mem_ctx);
907                 return LDB_ERR_OPERATIONS_ERROR;
908         }
909         
910         /* modify dn */
911         msg->dn = ac->req->op.mod.message->dn;
912
913         ret = objectclass_sort(ac->module, ac->schema, mem_ctx,
914                                objectclass_element, &sorted);
915         if (ret != LDB_SUCCESS) {
916                 return ret;
917         }
918
919         /* We must completely replace the existing objectClass entry.
920          * We could do a constrained add/del, but we are meant to be
921          * in a transaction... */
922
923         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
924         if (ret != LDB_SUCCESS) {
925                 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
926                 talloc_free(mem_ctx);
927                 return ret;
928         }
929         
930         /* Move from the linked list back into an ldb msg */
931         for (current = sorted; current; current = current->next) {
932                 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
933                 if (value == NULL) {
934                         ldb_oom(ldb);
935                         return LDB_ERR_OPERATIONS_ERROR;
936                 }
937                 ret = ldb_msg_add_string(msg, "objectClass", value);
938                 if (ret != LDB_SUCCESS) {
939                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
940                         talloc_free(mem_ctx);
941                         return ret;
942                 }
943         }
944
945         ret = ldb_msg_sanity_check(ldb, msg);
946         if (ret != LDB_SUCCESS) {
947                 talloc_free(mem_ctx);
948                 return ret;
949         }
950
951         ret = ldb_build_mod_req(&mod_req, ldb, ac,
952                                 msg,
953                                 ac->req->controls,
954                                 ac, oc_op_callback,
955                                 ac->req);
956         if (ret != LDB_SUCCESS) {
957                 talloc_free(mem_ctx);
958                 return ret;
959         }
960
961         talloc_free(mem_ctx);
962         /* perform the modify */
963         return ldb_next_request(ac->module, mod_req);
964 }
965
966 static int objectclass_do_rename(struct oc_context *ac);
967
968 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
969 {
970         static const char * const attrs[] = { "objectClass", NULL };
971         struct ldb_context *ldb;
972         struct ldb_request *search_req;
973         struct oc_context *ac;
974         struct ldb_dn *parent_dn;
975         int ret;
976
977         ldb = ldb_module_get_ctx(module);
978
979         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
980
981         /* do not manipulate our control entries */
982         if (ldb_dn_is_special(req->op.rename.newdn)) {
983                 return ldb_next_request(module, req);
984         }
985
986         ac = oc_init_context(module, req);
987         if (ac == NULL) {
988                 return LDB_ERR_OPERATIONS_ERROR;
989         }
990
991         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
992         if (parent_dn == NULL) {
993                 ldb_oom(ldb);
994                 return LDB_ERR_OPERATIONS_ERROR;
995         }
996
997         /* this looks up the parent object for fetching some important
998          * informations (objectclasses, DN normalisation...) */
999         ret = ldb_build_search_req(&search_req, ldb,
1000                                    ac, parent_dn, LDB_SCOPE_BASE,
1001                                    "(objectClass=*)",
1002                                    attrs, NULL,
1003                                    ac, get_search_callback,
1004                                    req);
1005         if (ret != LDB_SUCCESS) {
1006                 return ret;
1007         }
1008
1009         /* we have to add the show deleted control, as otherwise DRS
1010            deletes will be refused as we will think the target parent
1011            does not exist */
1012         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1013
1014         if (ret != LDB_SUCCESS) {
1015                 return ret;
1016         }
1017
1018         ac->step_fn = objectclass_do_rename;
1019
1020         return ldb_next_request(ac->module, search_req);
1021 }
1022
1023 static int objectclass_do_rename2(struct oc_context *ac);
1024
1025 static int objectclass_do_rename(struct oc_context *ac)
1026 {
1027         static const char * const attrs[] = { "objectClass", NULL };
1028         struct ldb_context *ldb;
1029         struct ldb_request *search_req;
1030         int ret;
1031
1032         ldb = ldb_module_get_ctx(ac->module);
1033
1034         /* Check if we have a valid parent - this check is needed since
1035          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1036         if (ac->search_res == NULL) {
1037                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!",
1038                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1039                 return LDB_ERR_OTHER;
1040         }
1041
1042         /* now assign "search_res2" to the parent entry to have "search_res"
1043          * free for another lookup */
1044         ac->search_res2 = ac->search_res;
1045         ac->search_res = NULL;
1046
1047         /* this looks up the real existing object for fetching some important
1048          * informations (objectclasses) */
1049         ret = ldb_build_search_req(&search_req, ldb,
1050                                    ac, ac->req->op.rename.olddn,
1051                                    LDB_SCOPE_BASE,
1052                                    "(objectClass=*)",
1053                                    attrs, NULL,
1054                                    ac, get_search_callback,
1055                                    ac->req);
1056         if (ret != LDB_SUCCESS) {
1057                 return ret;
1058         }
1059
1060         ac->step_fn = objectclass_do_rename2;
1061
1062         return ldb_next_request(ac->module, search_req);
1063 }
1064
1065 static int objectclass_do_rename2(struct oc_context *ac)
1066 {
1067         struct ldb_context *ldb;
1068         struct ldb_request *rename_req;
1069         struct ldb_dn *fixed_dn;
1070         int ret;
1071
1072         ldb = ldb_module_get_ctx(ac->module);
1073
1074         /* Check if we have a valid entry - this check is needed since
1075          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
1076         if (ac->search_res == NULL) {
1077                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, entry does not exist!",
1078                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1079                 return LDB_ERR_NO_SUCH_OBJECT;
1080         }
1081
1082         if (ac->schema != NULL) {
1083                 struct ldb_message_element *oc_el_entry, *oc_el_parent;
1084                 const struct dsdb_class *objectclass;
1085                 const char *rdn_name;
1086                 bool allowed_class = false;
1087                 unsigned int i, j;
1088
1089                 oc_el_entry = ldb_msg_find_element(ac->search_res->message,
1090                                                    "objectClass");
1091                 if (oc_el_entry == NULL) {
1092                         /* existing entry without a valid object class? */
1093                         return LDB_ERR_OPERATIONS_ERROR;
1094                 }
1095                 objectclass = get_last_structural_class(ac->schema, oc_el_entry);
1096                 if (objectclass == NULL) {
1097                         /* existing entry without a valid object class? */
1098                         return LDB_ERR_OPERATIONS_ERROR;
1099                 }
1100
1101                 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
1102                 if ((objectclass->rDNAttID != NULL) &&
1103                     (ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0)) {
1104                         ldb_asprintf_errstring(ldb,
1105                                                "objectclass: RDN %s is not correct for most specific structural objectclass %s, should be %s",
1106                                                rdn_name,
1107                                                objectclass->lDAPDisplayName,
1108                                                objectclass->rDNAttID);
1109                         return LDB_ERR_UNWILLING_TO_PERFORM;
1110                 }
1111
1112                 oc_el_parent = ldb_msg_find_element(ac->search_res2->message,
1113                                                     "objectClass");
1114                 if (oc_el_parent == NULL) {
1115                         /* existing entry without a valid object class? */
1116                         return LDB_ERR_OPERATIONS_ERROR;
1117                 }
1118
1119                 for (i=0; allowed_class == false && i < oc_el_parent->num_values; i++) {
1120                         const struct dsdb_class *sclass;
1121
1122                         sclass = dsdb_class_by_lDAPDisplayName_ldb_val(ac->schema,
1123                                                                        &oc_el_parent->values[i]);
1124                         if (!sclass) {
1125                                 /* We don't know this class?  what is going on? */
1126                                 continue;
1127                         }
1128                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
1129                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
1130                                         allowed_class = true;
1131                                         break;
1132                                 }
1133                         }
1134                 }
1135
1136                 if (!allowed_class) {
1137                         ldb_asprintf_errstring(ldb,
1138                                                "objectclass: structural objectClass %s is not a valid child class for %s",
1139                                                objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res2->message->dn));
1140                         return LDB_ERR_NAMING_VIOLATION;
1141                 }
1142         }
1143
1144         /* Ensure we are not trying to rename it to be a child of itself */
1145         if ((ldb_dn_compare_base(ac->req->op.rename.olddn,
1146                                  ac->req->op.rename.newdn) == 0)  &&
1147             (ldb_dn_compare(ac->req->op.rename.olddn,
1148                             ac->req->op.rename.newdn) != 0)) {
1149                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s to be a child of itself",
1150                                        ldb_dn_get_linearized(ac->req->op.rename.olddn));
1151                 return LDB_ERR_UNWILLING_TO_PERFORM;
1152         }
1153
1154         /* Fix up the DN to be in the standard form, taking
1155          * particular care to match the parent DN */
1156         ret = fix_dn(ac,
1157                      ac->req->op.rename.newdn,
1158                      ac->search_res2->message->dn,
1159                      &fixed_dn);
1160         if (ret != LDB_SUCCESS) {
1161                 ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
1162                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1163                 return ret;
1164
1165         }
1166
1167         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1168                                    ac->req->op.rename.olddn, fixed_dn,
1169                                    ac->req->controls,
1170                                    ac, oc_op_callback,
1171                                    ac->req);
1172         if (ret != LDB_SUCCESS) {
1173                 return ret;
1174         }
1175
1176         /* perform the rename */
1177         return ldb_next_request(ac->module, rename_req);
1178 }
1179
1180 static int objectclass_init(struct ldb_module *module)
1181 {
1182         struct ldb_context *ldb = ldb_module_get_ctx(module);
1183         int ret;
1184         /* Init everything else */
1185         ret = ldb_next_init(module);
1186         if (ret != LDB_SUCCESS) {
1187                 return ret;
1188         }
1189         
1190         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1191         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1192
1193         return ret;
1194 }
1195
1196 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1197         .name              = "objectclass",
1198         .add           = objectclass_add,
1199         .modify        = objectclass_modify,
1200         .rename        = objectclass_rename,
1201         .init_context  = objectclass_init
1202 };