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