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