s4:objectclass LDB module - cosmetic change
[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
55         struct ldb_reply *search_res;
56
57         int (*step_fn)(struct oc_context *);
58 };
59
60 struct class_list {
61         struct class_list *prev, *next;
62         const struct dsdb_class *objectclass;
63 };
64
65 static struct oc_context *oc_init_context(struct ldb_module *module,
66                                           struct ldb_request *req)
67 {
68         struct ldb_context *ldb;
69         struct oc_context *ac;
70
71         ldb = ldb_module_get_ctx(module);
72
73         ac = talloc_zero(req, struct oc_context);
74         if (ac == NULL) {
75                 ldb_oom(ldb);
76                 return NULL;
77         }
78
79         ac->module = module;
80         ac->req = req;
81
82         return ac;
83 }
84
85 static int objectclass_do_add(struct oc_context *ac);
86
87 /* Sort objectClasses into correct order, and validate that all
88  * objectClasses specified actually exist in the schema
89  */
90
91 static int objectclass_sort(struct ldb_module *module,
92                             const struct dsdb_schema *schema,
93                             TALLOC_CTX *mem_ctx,
94                             struct ldb_message_element *objectclass_element,
95                             struct class_list **sorted_out) 
96 {
97         struct ldb_context *ldb;
98         unsigned int i, lowest;
99         struct class_list *unsorted = NULL, *sorted = NULL, *current = NULL, *poss_parent = NULL, *new_parent = NULL, *current_lowest = NULL;
100
101         ldb = ldb_module_get_ctx(module);
102
103         /* DESIGN:
104          *
105          * We work on 4 different 'bins' (implemented here as linked lists):
106          *
107          * * sorted:       the eventual list, in the order we wish to push
108          *                 into the database.  This is the only ordered list.
109          *
110          * * parent_class: The current parent class 'bin' we are
111          *                 trying to find subclasses for
112          *
113          * * subclass:     The subclasses we have found so far
114          *
115          * * unsorted:     The remaining objectClasses
116          *
117          * The process is a matter of filtering objectClasses up from
118          * unsorted into sorted.  Order is irrelevent in the later 3 'bins'.
119          * 
120          * We start with 'top' (found and promoted to parent_class
121          * initially).  Then we find (in unsorted) all the direct
122          * subclasses of 'top'.  parent_classes is concatenated onto
123          * the end of 'sorted', and subclass becomes the list in
124          * parent_class.
125          *
126          * We then repeat, until we find no more subclasses.  Any left
127          * over classes are added to the end.
128          *
129          */
130
131         /* Firstly, dump all the objectClass elements into the
132          * unsorted bin, except for 'top', which is special */
133         for (i=0; i < objectclass_element->num_values; i++) {
134                 current = talloc(mem_ctx, struct class_list);
135                 if (!current) {
136                         ldb_oom(ldb);
137                         return LDB_ERR_OPERATIONS_ERROR;
138                 }
139                 current->objectclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &objectclass_element->values[i]);
140                 if (!current->objectclass) {
141                         ldb_asprintf_errstring(ldb, "objectclass %.*s is not a valid objectClass in schema", 
142                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
143                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
144                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
145                 } else if (current->objectclass->isDefunct) {
146                         ldb_asprintf_errstring(ldb, "objectclass %.*s marked as isDefunct objectClass in schema - not valid for new objects", 
147                                                (int)objectclass_element->values[i].length, (const char *)objectclass_element->values[i].data);
148                         /* This looks weird, but windows apparently returns this for invalid objectClass values */
149                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
150                 }
151
152                 /* Don't add top to list, we will do that later */
153                 if (ldb_attr_cmp("top", current->objectclass->lDAPDisplayName) != 0) {
154                         DLIST_ADD_END(unsorted, current, struct class_list *);
155                 }
156         }
157
158         /* Add top here, to prevent duplicates */
159         current = talloc(mem_ctx, struct class_list);
160         current->objectclass = dsdb_class_by_lDAPDisplayName(schema, "top");
161         DLIST_ADD_END(sorted, current, struct class_list *);
162
163
164         /* For each object:  find parent chain */
165         for (current = unsorted; schema && current; current = current->next) {
166                 for (poss_parent = unsorted; poss_parent; poss_parent = poss_parent->next) {
167                         if (ldb_attr_cmp(poss_parent->objectclass->lDAPDisplayName, current->objectclass->subClassOf) == 0) {
168                                 break;
169                         }
170                 }
171                 /* If we didn't get to the end of the list, we need to add this parent */
172                 if (poss_parent || (ldb_attr_cmp("top", current->objectclass->subClassOf) == 0)) {
173                         continue;
174                 }
175
176                 new_parent = talloc(mem_ctx, struct class_list);
177                 new_parent->objectclass = dsdb_class_by_lDAPDisplayName(schema, current->objectclass->subClassOf);
178                 DLIST_ADD_END(unsorted, new_parent, struct class_list *);
179         }
180
181         do
182         {
183                 lowest = UINT_MAX;
184                 current_lowest = NULL;
185                 for (current = unsorted; schema && current; current = current->next) {
186                         if(current->objectclass->subClass_order < lowest) {
187                                 current_lowest = current;
188                                 lowest = current->objectclass->subClass_order;
189                         }
190                 }
191
192                 if(current_lowest != NULL) {
193                         DLIST_REMOVE(unsorted,current_lowest);
194                         DLIST_ADD_END(sorted,current_lowest, struct class_list *);
195                 }
196         } while(unsorted);
197
198
199         if (!unsorted) {
200                 *sorted_out = sorted;
201                 return LDB_SUCCESS;
202         }
203
204         if (!schema) {
205                 /* If we don't have schema yet, then just merge the lists again */
206                 DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
207                 *sorted_out = sorted;
208                 return LDB_SUCCESS;
209         }
210
211         /* This shouldn't happen, and would break MMC, perhaps there
212          * was no 'top', a conflict in the objectClasses or some other
213          * schema error?
214          */
215         ldb_asprintf_errstring(ldb, "objectclass %s is not a valid objectClass in objectClass chain", unsorted->objectclass->lDAPDisplayName);
216         return LDB_ERR_OBJECT_CLASS_VIOLATION;
217 }
218
219 static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
220 {
221         struct ldb_context *ldb;
222         struct oc_context *ac;
223         int ret;
224
225         ac = talloc_get_type(req->context, struct oc_context);
226         ldb = ldb_module_get_ctx(ac->module);
227
228         if (!ares) {
229                 return ldb_module_done(ac->req, NULL, NULL,
230                                         LDB_ERR_OPERATIONS_ERROR);
231         }
232         if (ares->error != LDB_SUCCESS &&
233             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
234                 return ldb_module_done(ac->req, ares->controls,
235                                         ares->response, ares->error);
236         }
237
238         ldb_reset_err_string(ldb);
239
240         switch (ares->type) {
241         case LDB_REPLY_ENTRY:
242                 if (ac->search_res != NULL) {
243                         ldb_set_errstring(ldb, "Too many results");
244                         talloc_free(ares);
245                         return ldb_module_done(ac->req, NULL, NULL,
246                                                 LDB_ERR_OPERATIONS_ERROR);
247                 }
248
249                 ac->search_res = talloc_steal(ac, ares);
250                 break;
251
252         case LDB_REPLY_REFERRAL:
253                 /* ignore */
254                 talloc_free(ares);
255                 break;
256
257         case LDB_REPLY_DONE:
258                 talloc_free(ares);
259                 ret = ac->step_fn(ac);
260                 if (ret != LDB_SUCCESS) {
261                         return ldb_module_done(ac->req, NULL, NULL, ret);
262                 }
263                 break;
264         }
265
266         return LDB_SUCCESS;
267 }
268
269 static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
270 {
271         struct oc_context *ac;
272
273         ac = talloc_get_type(req->context, struct oc_context);
274
275         if (!ares) {
276                 return ldb_module_done(ac->req, NULL, NULL,
277                                         LDB_ERR_OPERATIONS_ERROR);
278         }
279
280         if (ares->type == LDB_REPLY_REFERRAL) {
281                 return ldb_module_send_referral(ac->req, ares->referral);
282         }
283
284         if (ares->error != LDB_SUCCESS) {
285                 return ldb_module_done(ac->req, ares->controls,
286                                         ares->response, ares->error);
287         }
288
289         if (ares->type != LDB_REPLY_DONE) {
290                 talloc_free(ares);
291                 return ldb_module_done(ac->req, NULL, NULL,
292                                         LDB_ERR_OPERATIONS_ERROR);
293         }
294
295         return ldb_module_done(ac->req, ares->controls,
296                                 ares->response, ares->error);
297 }
298
299 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
300
301    This should mean that if the parent is:
302     CN=Users,DC=samba,DC=example,DC=com
303    and a proposed child is
304     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
305
306    The resulting DN should be:
307
308     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
309    
310  */
311 static int fix_dn(TALLOC_CTX *mem_ctx, 
312                   struct ldb_dn *newdn, struct ldb_dn *parent_dn, 
313                   struct ldb_dn **fixed_dn) 
314 {
315         char *upper_rdn_attr;
316         const struct ldb_val *rdn_val;
317
318         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
319         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
320
321         /* We need the attribute name in upper case */
322         upper_rdn_attr = strupper_talloc(*fixed_dn, 
323                                          ldb_dn_get_rdn_name(newdn));
324         if (!upper_rdn_attr) {
325                 return LDB_ERR_OPERATIONS_ERROR;
326         }
327
328         /* Create a new child */
329         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
330                 return LDB_ERR_OPERATIONS_ERROR;
331         }
332
333
334         rdn_val = ldb_dn_get_rdn_val(newdn);
335
336 #if 0
337         /* the rules for rDN length constraints are more complex than
338         this. Until we understand them we need to leave this
339         constraint out. Otherwise we break replication, as windows
340         does sometimes send us rDNs longer than 64 */
341         if (!rdn_val || rdn_val->length > 64) {
342                 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
343         }
344 #endif
345
346
347         /* And replace it with CN=foo (we need the attribute in upper case */
348         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
349 }
350
351 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
352 static int fix_check_attributes(struct ldb_context *ldb,
353                                 const struct dsdb_schema *schema,
354                                 struct ldb_message *msg,
355                                 enum ldb_request_type op)
356 {
357         unsigned int i;
358         for (i=0; i < msg->num_elements; i++) {
359                 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
360                 /* Add in a very special case for 'clearTextPassword',
361                  * which is used for internal processing only, and is
362                  * not presented in the schema */
363                 if (!attribute) {
364                         if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
365                                 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
366                                 /* Apparently Windows sends exactly this behaviour */
367                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
368                         }
369                 } else {
370                         msg->elements[i].name = attribute->lDAPDisplayName;
371
372                         /* We have to deny write operations on constructed attributes */
373                         if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
374                                 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
375                                 if (op == LDB_ADD) {
376                                         return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
377                                 } else {
378                                         return LDB_ERR_CONSTRAINT_VIOLATION;
379                                 }
380                         }
381
382                 }
383         }
384
385         return LDB_SUCCESS;
386 }
387
388 static int objectclass_do_add(struct oc_context *ac);
389
390 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
391 {
392         struct ldb_context *ldb;
393         struct ldb_request *search_req;
394         struct oc_context *ac;
395         struct ldb_dn *parent_dn;
396         int ret;
397         static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
398
399         ldb = ldb_module_get_ctx(module);
400
401         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
402
403         /* do not manipulate our control entries */
404         if (ldb_dn_is_special(req->op.add.message->dn)) {
405                 return ldb_next_request(module, req);
406         }
407
408         /* the objectClass must be specified on add */
409         if (ldb_msg_find_element(req->op.add.message, 
410                                  "objectClass") == NULL) {
411                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
412         }
413
414         ac = oc_init_context(module, req);
415         if (ac == NULL) {
416                 return LDB_ERR_OPERATIONS_ERROR;
417         }
418
419         /* If there isn't a parent, just go on to the add processing */
420         if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
421                 return objectclass_do_add(ac);
422         }
423
424         /* get copy of parent DN */
425         parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
426         if (parent_dn == NULL) {
427                 ldb_oom(ldb);
428                 return LDB_ERR_OPERATIONS_ERROR;
429         }
430
431         ret = ldb_build_search_req(&search_req, ldb,
432                                    ac, parent_dn, LDB_SCOPE_BASE,
433                                    "(objectClass=*)", parent_attrs,
434                                    NULL,
435                                    ac, get_search_callback,
436                                    req);
437         if (ret != LDB_SUCCESS) {
438                 return ret;
439         }
440
441         ac->step_fn = objectclass_do_add;
442
443         return ldb_next_request(ac->module, search_req);
444 }
445
446 static int objectclass_do_add(struct oc_context *ac)
447 {
448         struct ldb_context *ldb;
449         const struct dsdb_schema *schema;
450         struct ldb_request *add_req;
451         char *value;
452         struct ldb_message_element *objectclass_element, *el;
453         struct ldb_message *msg;
454         TALLOC_CTX *mem_ctx;
455         struct class_list *sorted, *current;
456         int ret;
457         const struct dsdb_class *objectclass;
458         int32_t systemFlags = 0;
459         const char *rdn_name = NULL;
460
461         ldb = ldb_module_get_ctx(ac->module);
462         schema = dsdb_get_schema(ldb, ac);
463
464         mem_ctx = talloc_new(ac);
465         if (mem_ctx == NULL) {
466                 ldb_oom(ldb);
467                 return LDB_ERR_OPERATIONS_ERROR;
468         }
469
470         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
471
472         /* Check if we have a valid parent - this check is needed since
473          * we don't get a LDB_ERR_NO_SUCH_OBJECT error. */
474         if (ac->search_res == NULL) {
475                 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
476                         /* Allow the tree to be started */
477                         
478                         /* but don't keep any error string, it's meaningless */
479                         ldb_set_errstring(ldb, NULL);
480                 } else {
481                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
482                                                ldb_dn_get_linearized(msg->dn));
483                         talloc_free(mem_ctx);
484                         return LDB_ERR_NO_SUCH_OBJECT;
485                 }
486         } else {
487
488                 /* Fix up the DN to be in the standard form, taking
489                  * particular care to match the parent DN */
490                 ret = fix_dn(msg, 
491                              ac->req->op.add.message->dn,
492                              ac->search_res->message->dn,
493                              &msg->dn);
494
495                 if (ret != LDB_SUCCESS) {
496                         ldb_asprintf_errstring(ldb, "objectclass: Could not munge DN %s into normal form",
497                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
498                         talloc_free(mem_ctx);
499                         return ret;
500                 }
501
502         }
503         if (schema) {
504                 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
505                 if (ret != LDB_SUCCESS) {
506                         talloc_free(mem_ctx);
507                         return ret;
508                 }
509
510                 /* This is now the objectClass list from the database */
511                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
512
513                 if (!objectclass_element) {
514                         /* Where did it go?  bail now... */
515                         talloc_free(mem_ctx);
516                         return LDB_ERR_OPERATIONS_ERROR;
517                 }
518                 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
519                 if (ret != LDB_SUCCESS) {
520                         talloc_free(mem_ctx);
521                         return ret;
522                 }
523                 
524                 ldb_msg_remove_attr(msg, "objectClass");
525                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
526                 
527                 if (ret != LDB_SUCCESS) {
528                         talloc_free(mem_ctx);
529                         return ret;
530                 }
531
532                 /* We must completely replace the existing objectClass entry,
533                  * because we need it sorted */
534
535                 /* Move from the linked list back into an ldb msg */
536                 for (current = sorted; current; current = current->next) {
537                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
538                         if (value == NULL) {
539                                 ldb_oom(ldb);
540                                 talloc_free(mem_ctx);
541                                 return LDB_ERR_OPERATIONS_ERROR;
542                         }
543                         ret = ldb_msg_add_string(msg, "objectClass", value);
544                         if (ret != LDB_SUCCESS) {
545                                 ldb_set_errstring(ldb,
546                                                   "objectclass: could not re-add sorted "
547                                                   "objectclass to modify msg");
548                                 talloc_free(mem_ctx);
549                                 return ret;
550                         }
551                 }
552
553                 /* Retrive the message again so get_last_structural_class works */
554                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
555
556                 /* Make sure its valid to add an object of this type */
557                 objectclass = get_last_structural_class(schema,objectclass_element);
558                 if(objectclass == NULL) {
559                         ldb_asprintf_errstring(ldb,
560                                                "Failed to find a structural class for %s",
561                                                ldb_dn_get_linearized(msg->dn));
562                         return LDB_ERR_UNWILLING_TO_PERFORM;
563                 }
564
565                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
566                 if (objectclass->rDNAttID
567                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
568                         ldb_asprintf_errstring(ldb,
569                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
570                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
571                         return LDB_ERR_NAMING_VIOLATION;
572                 }
573
574                 if (ac->search_res && ac->search_res->message) {
575                         struct ldb_message_element *oc_el
576                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
577
578                         bool allowed_class = false;
579                         unsigned int i, j;
580                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
581                                 const struct dsdb_class *sclass;
582
583                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
584                                 if (!sclass) {
585                                         /* We don't know this class?  what is going on? */
586                                         continue;
587                                 }
588                                 for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
589                                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
590                                                 allowed_class = true;
591                                                 break;
592                                         }
593                                 }
594                         }
595
596                         if (!allowed_class) {
597                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
598                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
599                                 return LDB_ERR_NAMING_VIOLATION;
600                         }
601                 }
602
603                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
604                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
605                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
606                         return LDB_ERR_UNWILLING_TO_PERFORM;
607                 }
608
609                 if (!ldb_msg_find_element(msg, "objectCategory")) {
610                         struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
611                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
612                                 /* Strip off extended components */
613                                 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
614                                 value = ldb_dn_alloc_linearized(msg, dn);
615                                 talloc_free(dn);
616                         } else {
617                                 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
618                         }
619                         if (value == NULL) {
620                                 ldb_oom(ldb);
621                                 talloc_free(mem_ctx);
622                                 return LDB_ERR_OPERATIONS_ERROR;
623                         }
624                         ldb_msg_add_string(msg, "objectCategory", value);
625                 }
626                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
627                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
628                                                 "TRUE");
629                 }
630
631                 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
632                 el = ldb_msg_find_element(msg, "systemFlags");
633
634                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
635
636                 if (el) {
637                         /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
638                         /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
639                         ldb_msg_remove_element(msg, el);
640                 }
641
642                 /* This flag is only allowed on attributeSchema objects */
643                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
644                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
645                 }
646
647                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
648                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
649                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
650                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
651                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
652                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
653
654                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
655                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
656                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
657                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
658                 }
659
660                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
661
662                 if (el || systemFlags != 0) {
663                         samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
664                 }
665         }
666
667         talloc_free(mem_ctx);
668         ret = ldb_msg_sanity_check(ldb, msg);
669
670
671         if (ret != LDB_SUCCESS) {
672                 return ret;
673         }
674
675         ret = ldb_build_add_req(&add_req, ldb, ac,
676                                 msg,
677                                 ac->req->controls,
678                                 ac, oc_op_callback,
679                                 ac->req);
680         if (ret != LDB_SUCCESS) {
681                 return ret;
682         }
683
684         /* perform the add */
685         return ldb_next_request(ac->module, add_req);
686 }
687
688 static int oc_modify_callback(struct ldb_request *req,
689                                 struct ldb_reply *ares);
690 static int objectclass_do_mod(struct oc_context *ac);
691
692 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
693 {
694         struct ldb_context *ldb = ldb_module_get_ctx(module);
695         struct ldb_message_element *objectclass_element;
696         struct ldb_message *msg;
697         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
698         struct class_list *sorted, *current;
699         struct ldb_request *down_req;
700         struct oc_context *ac;
701         TALLOC_CTX *mem_ctx;
702         char *value;
703         int ret;
704
705         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
706
707         /* do not manipulate our control entries */
708         if (ldb_dn_is_special(req->op.mod.message->dn)) {
709                 return ldb_next_request(module, req);
710         }
711         
712         /* Without schema, there isn't much to do here */
713         if (!schema) {
714                 return ldb_next_request(module, req);
715         }
716
717         /* As with the "real" AD we don't accept empty messages */
718         if (req->op.mod.message->num_elements == 0) {
719                 ldb_set_errstring(ldb, "objectclass: modify message must have "
720                                        "elements/attributes!");
721                 return LDB_ERR_UNWILLING_TO_PERFORM;
722         }
723
724         ac = oc_init_context(module, req);
725         if (ac == NULL) {
726                 return LDB_ERR_OPERATIONS_ERROR;
727         }
728
729         if (!talloc_reference(ac, schema)) {
730                 ldb_oom(ldb);
731                 return LDB_ERR_OPERATIONS_ERROR;
732         }
733
734         /* If no part of this touches the objectClass, then we don't
735          * need to make any changes.  */
736         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
737
738         /* If the only operation is the deletion of the objectClass
739          * then go on with just fixing the attribute case */
740         if (!objectclass_element) {
741                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
742                 if (msg == NULL) {
743                         return LDB_ERR_OPERATIONS_ERROR;
744                 }
745                 
746                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
747                 if (ret != LDB_SUCCESS) {
748                         return ret;
749                 }
750
751                 ret = ldb_build_mod_req(&down_req, ldb, ac,
752                                         msg,
753                                         req->controls,
754                                         ac, oc_op_callback,
755                                         req);
756                 if (ret != LDB_SUCCESS) {
757                         return ret;
758                 }
759
760                 /* go on with the call chain */
761                 return ldb_next_request(module, down_req);
762         }
763
764         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
765         case LDB_FLAG_MOD_DELETE:
766                 if (objectclass_element->num_values == 0) {
767                         return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
768                 }
769                 break;
770
771         case LDB_FLAG_MOD_REPLACE:
772                 mem_ctx = talloc_new(ac);
773                 if (mem_ctx == NULL) {
774                         return LDB_ERR_OPERATIONS_ERROR;
775                 }
776
777                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
778                 if (msg == NULL) {
779                         talloc_free(mem_ctx);
780                         return LDB_ERR_OPERATIONS_ERROR;
781                 }
782
783                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
784                 if (ret != LDB_SUCCESS) {
785                         talloc_free(mem_ctx);
786                         return ret;
787                 }
788
789                 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
790                 if (ret != LDB_SUCCESS) {
791                         talloc_free(mem_ctx);
792                         return ret;
793                 }
794
795                 /* We must completely replace the existing objectClass entry,
796                  * because we need it sorted */
797                 
798                 ldb_msg_remove_attr(msg, "objectClass");
799                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
800                 
801                 if (ret != LDB_SUCCESS) {
802                         talloc_free(mem_ctx);
803                         return ret;
804                 }
805
806                 /* Move from the linked list back into an ldb msg */
807                 for (current = sorted; current; current = current->next) {
808                         /* copy the value as this string is on the schema
809                          * context and we can't rely on it not changing
810                          * before the operation is over */
811                         value = talloc_strdup(msg,
812                                         current->objectclass->lDAPDisplayName);
813                         if (value == NULL) {
814                                 ldb_oom(ldb);
815                                 talloc_free(mem_ctx);
816                                 return LDB_ERR_OPERATIONS_ERROR;
817                         }
818                         ret = ldb_msg_add_string(msg, "objectClass", value);
819                         if (ret != LDB_SUCCESS) {
820                                 ldb_set_errstring(ldb,
821                                         "objectclass: could not re-add sorted "
822                                         "objectclass to modify msg");
823                                 talloc_free(mem_ctx);
824                                 return ret;
825                         }
826                 }
827                 
828                 talloc_free(mem_ctx);
829
830                 ret = ldb_msg_sanity_check(ldb, msg);
831                 if (ret != LDB_SUCCESS) {
832                         return ret;
833                 }
834
835                 ret = ldb_build_mod_req(&down_req, ldb, ac,
836                                         msg,
837                                         req->controls,
838                                         ac, oc_op_callback,
839                                         req);
840                 if (ret != LDB_SUCCESS) {
841                         return ret;
842                 }
843
844                 /* go on with the call chain */
845                 return ldb_next_request(module, down_req);
846         }
847
848         /* This isn't the default branch of the switch, but a 'in any
849          * other case'.  When a delete isn't for all objectClasses for
850          * example
851          */
852
853         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
854         if (msg == NULL) {
855                 ldb_oom(ldb);
856                 return LDB_ERR_OPERATIONS_ERROR;
857         }
858
859         ret = fix_check_attributes(ldb, schema, msg, req->operation);
860         if (ret != LDB_SUCCESS) {
861                 ldb_oom(ldb);
862                 return ret;
863         }
864
865         ret = ldb_build_mod_req(&down_req, ldb, ac,
866                                 msg,
867                                 req->controls,
868                                 ac, oc_modify_callback,
869                                 req);
870         if (ret != LDB_SUCCESS) {
871                 return ret;
872         }
873
874         return ldb_next_request(module, down_req);
875 }
876
877 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
878 {
879         struct ldb_context *ldb;
880         static const char * const attrs[] = { "objectClass", NULL };
881         struct ldb_request *search_req;
882         struct oc_context *ac;
883         int ret;
884
885         ac = talloc_get_type(req->context, struct oc_context);
886         ldb = ldb_module_get_ctx(ac->module);
887
888         if (!ares) {
889                 return ldb_module_done(ac->req, NULL, NULL,
890                                         LDB_ERR_OPERATIONS_ERROR);
891         }
892
893         if (ares->type == LDB_REPLY_REFERRAL) {
894                 return ldb_module_send_referral(ac->req, ares->referral);
895         }
896
897         if (ares->error != LDB_SUCCESS) {
898                 return ldb_module_done(ac->req, ares->controls,
899                                         ares->response, ares->error);
900         }
901
902         if (ares->type != LDB_REPLY_DONE) {
903                 talloc_free(ares);
904                 return ldb_module_done(ac->req, NULL, NULL,
905                                         LDB_ERR_OPERATIONS_ERROR);
906         }
907
908         talloc_free(ares);
909
910         ret = ldb_build_search_req(&search_req, ldb, ac,
911                                    ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
912                                    "(objectClass=*)",
913                                    attrs, NULL, 
914                                    ac, get_search_callback,
915                                    ac->req);
916         if (ret != LDB_SUCCESS) {
917                 return ldb_module_done(ac->req, NULL, NULL, ret);
918         }
919
920         ac->step_fn = objectclass_do_mod;
921
922         ret = ldb_next_request(ac->module, search_req);
923         if (ret != LDB_SUCCESS) {
924                 return ldb_module_done(ac->req, NULL, NULL, ret);
925         }
926         return LDB_SUCCESS;
927 }
928
929 static int objectclass_do_mod(struct oc_context *ac)
930 {
931         struct ldb_context *ldb;
932         const struct dsdb_schema *schema;
933         struct ldb_request *mod_req;
934         char *value;
935         struct ldb_message_element *objectclass_element;
936         struct ldb_message *msg;
937         TALLOC_CTX *mem_ctx;
938         struct class_list *sorted, *current;
939         int ret;
940
941         ldb = ldb_module_get_ctx(ac->module);
942
943         if (ac->search_res == NULL) {
944                 return LDB_ERR_OPERATIONS_ERROR;
945         }
946         schema = dsdb_get_schema(ldb, ac);
947
948         mem_ctx = talloc_new(ac);
949         if (mem_ctx == NULL) {
950                 return LDB_ERR_OPERATIONS_ERROR;
951         }
952
953         /* use a new message structure */
954         msg = ldb_msg_new(ac);
955         if (msg == NULL) {
956                 ldb_set_errstring(ldb,
957                         "objectclass: could not create new modify msg");
958                 talloc_free(mem_ctx);
959                 return LDB_ERR_OPERATIONS_ERROR;
960         }
961
962         /* This is now the objectClass list from the database */
963         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
964                                                    "objectClass");
965         if (!objectclass_element) {
966                 /* Where did it go?  bail now... */
967                 talloc_free(mem_ctx);
968                 return LDB_ERR_OPERATIONS_ERROR;
969         }
970         
971         /* modify dn */
972         msg->dn = ac->req->op.mod.message->dn;
973
974         ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
975         if (ret != LDB_SUCCESS) {
976                 return ret;
977         }
978
979         /* We must completely replace the existing objectClass entry.
980          * We could do a constrained add/del, but we are meant to be
981          * in a transaction... */
982
983         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
984         if (ret != LDB_SUCCESS) {
985                 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
986                 talloc_free(mem_ctx);
987                 return ret;
988         }
989         
990         /* Move from the linked list back into an ldb msg */
991         for (current = sorted; current; current = current->next) {
992                 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
993                 if (value == NULL) {
994                         ldb_oom(ldb);
995                         return LDB_ERR_OPERATIONS_ERROR;
996                 }
997                 ret = ldb_msg_add_string(msg, "objectClass", value);
998                 if (ret != LDB_SUCCESS) {
999                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1000                         talloc_free(mem_ctx);
1001                         return ret;
1002                 }
1003         }
1004
1005         ret = ldb_msg_sanity_check(ldb, msg);
1006         if (ret != LDB_SUCCESS) {
1007                 talloc_free(mem_ctx);
1008                 return ret;
1009         }
1010
1011         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1012                                 msg,
1013                                 ac->req->controls,
1014                                 ac, oc_op_callback,
1015                                 ac->req);
1016         if (ret != LDB_SUCCESS) {
1017                 talloc_free(mem_ctx);
1018                 return ret;
1019         }
1020
1021         talloc_free(mem_ctx);
1022         /* perform the modify */
1023         return ldb_next_request(ac->module, mod_req);
1024 }
1025
1026 static int objectclass_do_rename(struct oc_context *ac);
1027
1028 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1029 {
1030         static const char * const attrs[] = { NULL };
1031         struct ldb_context *ldb;
1032         struct ldb_request *search_req;
1033         struct oc_context *ac;
1034         struct ldb_dn *parent_dn;
1035         int ret;
1036
1037         ldb = ldb_module_get_ctx(module);
1038
1039         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1040
1041         if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1042                 return ldb_next_request(module, req);
1043         }
1044
1045         /* Firstly ensure we are not trying to rename it to be a child of itself */
1046         if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
1047             && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1048                 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1049                                        ldb_dn_get_linearized(req->op.rename.olddn));
1050                 return LDB_ERR_UNWILLING_TO_PERFORM;
1051         }
1052
1053         ac = oc_init_context(module, req);
1054         if (ac == NULL) {
1055                 return LDB_ERR_OPERATIONS_ERROR;
1056         }
1057
1058         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1059         if (parent_dn == NULL) {
1060                 ldb_oom(ldb);
1061                 return LDB_ERR_OPERATIONS_ERROR;
1062         }
1063
1064         /*
1065           it makes a search request, looking for the parent DN to fix up the new DN
1066           to a standard one, at objectclass_do_rename()
1067          */
1068         ret = ldb_build_search_req(&search_req, ldb,
1069                                    ac, parent_dn, LDB_SCOPE_BASE,
1070                                    "(objectClass=*)",
1071                                    attrs, NULL,
1072                                    ac, get_search_callback,
1073                                    req);
1074         if (ret != LDB_SUCCESS) {
1075                 return ret;
1076         }
1077
1078         /* we have to add the show deleted control, as otherwise DRS
1079            deletes will be refused as we will think the target parent
1080            does not exist */
1081         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1082
1083         if (ret != LDB_SUCCESS) {
1084                 return ret;
1085         }
1086
1087         ac->step_fn = objectclass_do_rename;
1088
1089         return ldb_next_request(ac->module, search_req);
1090
1091
1092 }
1093
1094 static int objectclass_do_rename(struct oc_context *ac)
1095 {
1096         struct ldb_context *ldb;
1097         struct ldb_request *rename_req;
1098         struct ldb_dn *fixed_dn;
1099         int ret;
1100
1101         ldb = ldb_module_get_ctx(ac->module);
1102
1103         /* Check we have a valid parent */
1104         if (ac->search_res == NULL) {
1105                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!", 
1106                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1107                 return LDB_ERR_UNWILLING_TO_PERFORM;
1108         }
1109         
1110         /* Fix up the DN to be in the standard form,
1111          * taking particular care to match the parent DN */
1112         ret = fix_dn(ac,
1113                      ac->req->op.rename.newdn,
1114                      ac->search_res->message->dn,
1115                      &fixed_dn);
1116         if (ret != LDB_SUCCESS) {
1117                 return ret;
1118         }
1119
1120         /* TODO: Check this is a valid child to this parent,
1121          * by reading the allowedChildClasses and
1122          * allowedChildClasssesEffective attributes */
1123
1124         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1125                                    ac->req->op.rename.olddn, fixed_dn,
1126                                    ac->req->controls,
1127                                    ac, oc_op_callback,
1128                                    ac->req);
1129         if (ret != LDB_SUCCESS) {
1130                 return ret;
1131         }
1132
1133         /* perform the rename */
1134         return ldb_next_request(ac->module, rename_req);
1135 }
1136
1137 static int objectclass_init(struct ldb_module *module)
1138 {
1139         struct ldb_context *ldb = ldb_module_get_ctx(module);
1140         int ret;
1141         /* Init everything else */
1142         ret = ldb_next_init(module);
1143         if (ret != LDB_SUCCESS) {
1144                 return ret;
1145         }
1146         
1147         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1148         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1149
1150         return ret;
1151 }
1152
1153 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1154         .name              = "objectclass",
1155         .add           = objectclass_add,
1156         .modify        = objectclass_modify,
1157         .rename        = objectclass_rename,
1158         .init_context  = objectclass_init
1159 };