s4/rodc: Fix the callbacks up the stack to handle referrals on modify requests
[samba.git] / source4 / dsdb / samdb / ldb_modules / objectclass.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2006-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
6
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
278         if (ares->type == LDB_REPLY_REFERRAL) {
279                 return ldb_module_send_referral(ac->req, ares->referral);
280         }
281
282         if (ares->error != LDB_SUCCESS) {
283                 return ldb_module_done(ac->req, ares->controls,
284                                         ares->response, ares->error);
285         }
286
287         if (ares->type != LDB_REPLY_DONE) {
288                 talloc_free(ares);
289                 return ldb_module_done(ac->req, NULL, NULL,
290                                         LDB_ERR_OPERATIONS_ERROR);
291         }
292
293         return ldb_module_done(ac->req, ares->controls,
294                                 ares->response, ares->error);
295 }
296
297 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
298
299    This should mean that if the parent is:
300     CN=Users,DC=samba,DC=example,DC=com
301    and a proposed child is
302     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
303
304    The resulting DN should be:
305
306     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
307    
308  */
309 static int fix_dn(TALLOC_CTX *mem_ctx, 
310                   struct ldb_dn *newdn, struct ldb_dn *parent_dn, 
311                   struct ldb_dn **fixed_dn) 
312 {
313         char *upper_rdn_attr;
314         const struct ldb_val *rdn_val;
315
316         /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
317         *fixed_dn = ldb_dn_copy(mem_ctx, parent_dn);
318
319         /* We need the attribute name in upper case */
320         upper_rdn_attr = strupper_talloc(*fixed_dn, 
321                                          ldb_dn_get_rdn_name(newdn));
322         if (!upper_rdn_attr) {
323                 return LDB_ERR_OPERATIONS_ERROR;
324         }
325
326         /* Create a new child */
327         if (ldb_dn_add_child_fmt(*fixed_dn, "X=X") == false) {
328                 return LDB_ERR_OPERATIONS_ERROR;
329         }
330
331
332         rdn_val = ldb_dn_get_rdn_val(newdn);
333
334 #if 0
335         /* the rules for rDN length constraints are more complex than
336         this. Until we understand them we need to leave this
337         constraint out. Otherwise we break replication, as windows
338         does sometimes send us rDNs longer than 64 */
339         if (!rdn_val || rdn_val->length > 64) {
340                 DEBUG(2,(__location__ ": WARNING: rDN longer than 64 limit for '%s'\n", ldb_dn_get_linearized(newdn)));
341         }
342 #endif
343
344
345         /* And replace it with CN=foo (we need the attribute in upper case */
346         return ldb_dn_set_component(*fixed_dn, 0, upper_rdn_attr, *rdn_val);
347 }
348
349 /* Fix all attribute names to be in the correct case, and check they are all valid per the schema */
350 static int fix_check_attributes(struct ldb_context *ldb,
351                                 const struct dsdb_schema *schema,
352                                 struct ldb_message *msg,
353                                 enum ldb_request_type op)
354 {
355         unsigned int i;
356         for (i=0; i < msg->num_elements; i++) {
357                 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
358                 /* Add in a very special case for 'clearTextPassword',
359                  * which is used for internal processing only, and is
360                  * not presented in the schema */
361                 if (!attribute) {
362                         if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
363                                 ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
364                                 /* Apparently Windows sends exactly this behaviour */
365                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
366                         }
367                 } else {
368                         msg->elements[i].name = attribute->lDAPDisplayName;
369
370                         /* We have to deny write operations on constructed attributes */
371                         if ((attribute->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED) != 0) {
372                                 ldb_asprintf_errstring(ldb, "attribute %s is constructed", msg->elements[i].name);
373                                 if (op == LDB_ADD) {
374                                         return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
375                                 } else {
376                                         return LDB_ERR_CONSTRAINT_VIOLATION;
377                                 }
378                         }
379
380                 }
381         }
382
383         return LDB_SUCCESS;
384 }
385
386 static int objectclass_do_add(struct oc_context *ac);
387
388 static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
389 {
390         struct ldb_context *ldb;
391         struct ldb_request *search_req;
392         struct oc_context *ac;
393         struct ldb_dn *parent_dn;
394         int ret;
395         static const char * const parent_attrs[] = { "objectGUID", "objectClass", NULL };
396
397         ldb = ldb_module_get_ctx(module);
398
399         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
400
401         /* do not manipulate our control entries */
402         if (ldb_dn_is_special(req->op.add.message->dn)) {
403                 return ldb_next_request(module, req);
404         }
405
406         /* the objectClass must be specified on add */
407         if (ldb_msg_find_element(req->op.add.message, 
408                                  "objectClass") == NULL) {
409                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
410         }
411
412         ac = oc_init_context(module, req);
413         if (ac == NULL) {
414                 return LDB_ERR_OPERATIONS_ERROR;
415         }
416
417         /* If there isn't a parent, just go on to the add processing */
418         if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
419                 return objectclass_do_add(ac);
420         }
421
422         /* get copy of parent DN */
423         parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
424         if (parent_dn == NULL) {
425                 ldb_oom(ldb);
426                 return LDB_ERR_OPERATIONS_ERROR;
427         }
428
429         ret = ldb_build_search_req(&search_req, ldb,
430                                    ac, parent_dn, LDB_SCOPE_BASE,
431                                    "(objectClass=*)", parent_attrs,
432                                    NULL,
433                                    ac, get_search_callback,
434                                    req);
435         if (ret != LDB_SUCCESS) {
436                 return ret;
437         }
438         talloc_steal(search_req, parent_dn);
439
440         ac->step_fn = objectclass_do_add;
441
442         return ldb_next_request(ac->module, search_req);
443 }
444
445 static int objectclass_do_add(struct oc_context *ac)
446 {
447         struct ldb_context *ldb;
448         const struct dsdb_schema *schema;
449         struct ldb_request *add_req;
450         char *value;
451         struct ldb_message_element *objectclass_element, *el;
452         struct ldb_message *msg;
453         TALLOC_CTX *mem_ctx;
454         struct class_list *sorted, *current;
455         int ret;
456         const struct dsdb_class *objectclass;
457         int32_t systemFlags = 0;
458         const char *rdn_name = NULL;
459
460         ldb = ldb_module_get_ctx(ac->module);
461         schema = dsdb_get_schema(ldb, ac);
462
463         mem_ctx = talloc_new(ac);
464         if (mem_ctx == NULL) {
465                 ldb_oom(ldb);
466                 return LDB_ERR_OPERATIONS_ERROR;
467         }
468
469         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
470
471         /* Check we have a valid parent */
472         if (ac->search_res == NULL) {
473                 if (ldb_dn_compare(ldb_get_root_basedn(ldb), msg->dn) == 0) {
474                         /* Allow the tree to be started */
475                         
476                         /* but don't keep any error string, it's meaningless */
477                         ldb_set_errstring(ldb, NULL);
478                 } else {
479                         ldb_asprintf_errstring(ldb, "objectclass: Cannot add %s, parent does not exist!", 
480                                                ldb_dn_get_linearized(msg->dn));
481                         talloc_free(mem_ctx);
482                         return LDB_ERR_NO_SUCH_OBJECT;
483                 }
484         } else {
485
486                 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
487                 ret = fix_dn(msg, 
488                              ac->req->op.add.message->dn,
489                              ac->search_res->message->dn,
490                              &msg->dn);
491
492                 if (ret != LDB_SUCCESS) {
493                         ldb_asprintf_errstring(ldb, "Could not munge DN %s into normal form", 
494                                                ldb_dn_get_linearized(ac->req->op.add.message->dn));
495                         talloc_free(mem_ctx);
496                         return ret;
497                 }
498
499         }
500         if (schema) {
501                 ret = fix_check_attributes(ldb, schema, msg, ac->req->operation);
502                 if (ret != LDB_SUCCESS) {
503                         talloc_free(mem_ctx);
504                         return ret;
505                 }
506
507                 /* This is now the objectClass list from the database */
508                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
509
510                 if (!objectclass_element) {
511                         /* Where did it go?  bail now... */
512                         talloc_free(mem_ctx);
513                         return LDB_ERR_OPERATIONS_ERROR;
514                 }
515                 ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
516                 if (ret != LDB_SUCCESS) {
517                         talloc_free(mem_ctx);
518                         return ret;
519                 }
520                 
521                 ldb_msg_remove_attr(msg, "objectClass");
522                 ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
523                 
524                 if (ret != LDB_SUCCESS) {
525                         talloc_free(mem_ctx);
526                         return ret;
527                 }
528
529                 /* We must completely replace the existing objectClass entry,
530                  * because we need it sorted */
531
532                 /* Move from the linked list back into an ldb msg */
533                 for (current = sorted; current; current = current->next) {
534                         value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
535                         if (value == NULL) {
536                                 ldb_oom(ldb);
537                                 talloc_free(mem_ctx);
538                                 return LDB_ERR_OPERATIONS_ERROR;
539                         }
540                         ret = ldb_msg_add_string(msg, "objectClass", value);
541                         if (ret != LDB_SUCCESS) {
542                                 ldb_set_errstring(ldb,
543                                                   "objectclass: could not re-add sorted "
544                                                   "objectclass to modify msg");
545                                 talloc_free(mem_ctx);
546                                 return ret;
547                         }
548                 }
549
550                 /* Retrive the message again so get_last_structural_class works */
551                 objectclass_element = ldb_msg_find_element(msg, "objectClass");
552
553                 /* Make sure its valid to add an object of this type */
554                 objectclass = get_last_structural_class(schema,objectclass_element);
555                 if(objectclass == NULL) {
556                         ldb_asprintf_errstring(ldb,
557                                                 "Failed to find a structural class for %s",
558                                                   ldb_dn_get_linearized(msg->dn));
559                         return LDB_ERR_NAMING_VIOLATION;
560                 }
561
562                 rdn_name = ldb_dn_get_rdn_name(msg->dn);
563                 if (objectclass->rDNAttID
564                         && ldb_attr_cmp(rdn_name, objectclass->rDNAttID) != 0) {
565                         ldb_asprintf_errstring(ldb,
566                                                 "RDN %s is not correct for most specific structural objectclass %s, should be %s",
567                                                 rdn_name, objectclass->lDAPDisplayName, objectclass->rDNAttID);
568                         return LDB_ERR_NAMING_VIOLATION;
569                 }
570
571                 if (ac->search_res && ac->search_res->message) {
572                         struct ldb_message_element *oc_el
573                                 = ldb_msg_find_element(ac->search_res->message, "objectClass");
574
575                         bool allowed_class = false;
576                         int i, j;
577                         for (i=0; allowed_class == false && oc_el && i < oc_el->num_values; i++) {
578                                 const struct dsdb_class *sclass;
579
580                                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
581                                 if (!sclass) {
582                                         /* We don't know this class?  what is going on? */
583                                         continue;
584                                 }
585                                 if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
586                                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
587                                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
588                                                         allowed_class = true;
589                                                         break;
590                                                 }
591                                         }
592                                 } else {
593                                         for (j=0; sclass->systemPossibleInferiors && sclass->systemPossibleInferiors[j]; j++) {
594                                                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, sclass->systemPossibleInferiors[j]) == 0) {
595                                                         allowed_class = true;
596                                                         break;
597                                                 }
598                                         }
599                                 }
600                         }
601
602                         if (!allowed_class) {
603                                 ldb_asprintf_errstring(ldb, "structural objectClass %s is not a valid child class for %s",
604                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(ac->search_res->message->dn));
605                                 return LDB_ERR_NAMING_VIOLATION;
606                         }
607                 }
608
609                 if (objectclass->systemOnly && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
610                         ldb_asprintf_errstring(ldb, "objectClass %s is systemOnly, rejecting creation of %s",
611                                                 objectclass->lDAPDisplayName, ldb_dn_get_linearized(msg->dn));
612                         return LDB_ERR_UNWILLING_TO_PERFORM;
613                 }
614
615                 if (!ldb_msg_find_element(msg, "objectCategory")) {
616                         struct dsdb_extended_dn_store_format *dn_format = talloc_get_type(ldb_module_get_private(ac->module), struct dsdb_extended_dn_store_format);
617                         if (dn_format && dn_format->store_extended_dn_in_ldb == false) {
618                                 /* Strip off extended components */
619                                 struct ldb_dn *dn = ldb_dn_new(msg, ldb, objectclass->defaultObjectCategory);
620                                 value = ldb_dn_alloc_linearized(msg, dn);
621                                 talloc_free(dn);
622                         } else {
623                                 value = talloc_strdup(msg, objectclass->defaultObjectCategory);
624                         }
625                         if (value == NULL) {
626                                 ldb_oom(ldb);
627                                 talloc_free(mem_ctx);
628                                 return LDB_ERR_OPERATIONS_ERROR;
629                         }
630                         ldb_msg_add_string(msg, "objectCategory", value);
631                 }
632                 if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (objectclass->defaultHidingValue == true)) {
633                         ldb_msg_add_string(msg, "showInAdvancedViewOnly",
634                                                 "TRUE");
635                 }
636
637                 /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */
638                 el = ldb_msg_find_element(msg, "systemFlags");
639
640                 systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
641
642                 if (el) {
643                         /* Only these flags may be set by a client, but we can't tell between a client and our provision at this point */
644                         /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */
645                         ldb_msg_remove_element(msg, el);
646                 }
647
648                 /* This flag is only allowed on attributeSchema objects */
649                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "attributeSchema") == 0) {
650                         systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN;
651                 }
652
653                 if (ldb_attr_cmp(objectclass->lDAPDisplayName, "server") == 0) {
654                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE | SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE);
655                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "site") == 0
656                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "serverContainer") == 0
657                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "ntDSDSA") == 0) {
658                         systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
659
660                 } else if (ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLink") == 0
661                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "siteLinkBridge") == 0
662                                 || ldb_attr_cmp(objectclass->lDAPDisplayName, "nTDSConnection") == 0) {
663                         systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME);
664                 }
665
666                 /* TODO: If parent object is site or subnet, also add (SYSTEM_FLAG_CONFIG_ALLOW_RENAME) */
667
668                 if (el || systemFlags != 0) {
669                         samdb_msg_add_int(ldb, msg, msg, "systemFlags", systemFlags);
670                 }
671         }
672
673         talloc_free(mem_ctx);
674         ret = ldb_msg_sanity_check(ldb, msg);
675
676
677         if (ret != LDB_SUCCESS) {
678                 return ret;
679         }
680
681         ret = ldb_build_add_req(&add_req, ldb, ac,
682                                 msg,
683                                 ac->req->controls,
684                                 ac, oc_op_callback,
685                                 ac->req);
686         if (ret != LDB_SUCCESS) {
687                 return ret;
688         }
689
690         /* perform the add */
691         return ldb_next_request(ac->module, add_req);
692 }
693
694 static int oc_modify_callback(struct ldb_request *req,
695                                 struct ldb_reply *ares);
696 static int objectclass_do_mod(struct oc_context *ac);
697
698 static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
699 {
700         struct ldb_context *ldb = ldb_module_get_ctx(module);
701         struct ldb_message_element *objectclass_element;
702         struct ldb_message *msg;
703         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
704         struct class_list *sorted, *current;
705         struct ldb_request *down_req;
706         struct oc_context *ac;
707         TALLOC_CTX *mem_ctx;
708         char *value;
709         int ret;
710
711         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
712
713         /* do not manipulate our control entries */
714         if (ldb_dn_is_special(req->op.mod.message->dn)) {
715                 return ldb_next_request(module, req);
716         }
717         
718         /* Without schema, there isn't much to do here */
719         if (!schema) {
720                 return ldb_next_request(module, req);
721         }
722
723         /* As with the "real" AD we don't accept empty messages */
724         if (req->op.mod.message->num_elements == 0) {
725                 ldb_set_errstring(ldb, "objectclass: modify message must have "
726                                        "elements/attributes!");
727                 return LDB_ERR_UNWILLING_TO_PERFORM;
728         }
729
730         ac = oc_init_context(module, req);
731         if (ac == NULL) {
732                 ldb_oom(ldb);
733                 return LDB_ERR_OPERATIONS_ERROR;
734         }
735
736         if (!talloc_reference(ac, schema)) {
737                 ldb_oom(ldb);
738                 return LDB_ERR_OPERATIONS_ERROR;
739         }
740
741         /* If no part of this touches the objectClass, then we don't
742          * need to make any changes.  */
743         objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
744
745         /* If the only operation is the deletion of the objectClass
746          * then go on with just fixing the attribute case */
747         if (!objectclass_element) {
748                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
749                 if (msg == NULL) {
750                         return LDB_ERR_OPERATIONS_ERROR;
751                 }
752                 
753                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
754                 if (ret != LDB_SUCCESS) {
755                         return ret;
756                 }
757
758                 ret = ldb_build_mod_req(&down_req, ldb, ac,
759                                         msg,
760                                         req->controls,
761                                         ac, oc_op_callback,
762                                         req);
763                 if (ret != LDB_SUCCESS) {
764                         return ret;
765                 }
766
767                 /* go on with the call chain */
768                 return ldb_next_request(module, down_req);
769         }
770
771         switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
772         case LDB_FLAG_MOD_DELETE:
773                 if (objectclass_element->num_values == 0) {
774                         return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
775                 }
776                 break;
777
778         case LDB_FLAG_MOD_REPLACE:
779                 mem_ctx = talloc_new(ac);
780                 if (mem_ctx == NULL) {
781                         return LDB_ERR_OPERATIONS_ERROR;
782                 }
783
784                 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
785                 if (msg == NULL) {
786                         talloc_free(mem_ctx);
787                         return LDB_ERR_OPERATIONS_ERROR;
788                 }
789
790                 ret = fix_check_attributes(ldb, schema, msg, req->operation);
791                 if (ret != LDB_SUCCESS) {
792                         talloc_free(mem_ctx);
793                         return ret;
794                 }
795
796                 ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
797                 if (ret != LDB_SUCCESS) {
798                         talloc_free(mem_ctx);
799                         return ret;
800                 }
801
802                 /* We must completely replace the existing objectClass entry,
803                  * because we need it sorted */
804                 
805                 ldb_msg_remove_attr(msg, "objectClass");
806                 ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
807                 
808                 if (ret != LDB_SUCCESS) {
809                         talloc_free(mem_ctx);
810                         return ret;
811                 }
812
813                 /* Move from the linked list back into an ldb msg */
814                 for (current = sorted; current; current = current->next) {
815                         /* copy the value as this string is on the schema
816                          * context and we can't rely on it not changing
817                          * before the operation is over */
818                         value = talloc_strdup(msg,
819                                         current->objectclass->lDAPDisplayName);
820                         if (value == NULL) {
821                                 ldb_oom(ldb);
822                                 talloc_free(mem_ctx);
823                                 return LDB_ERR_OPERATIONS_ERROR;
824                         }
825                         ret = ldb_msg_add_string(msg, "objectClass", value);
826                         if (ret != LDB_SUCCESS) {
827                                 ldb_set_errstring(ldb,
828                                         "objectclass: could not re-add sorted "
829                                         "objectclass to modify msg");
830                                 talloc_free(mem_ctx);
831                                 return ret;
832                         }
833                 }
834                 
835                 talloc_free(mem_ctx);
836
837                 ret = ldb_msg_sanity_check(ldb, msg);
838                 if (ret != LDB_SUCCESS) {
839                         return ret;
840                 }
841
842                 ret = ldb_build_mod_req(&down_req, ldb, ac,
843                                         msg,
844                                         req->controls,
845                                         ac, oc_op_callback,
846                                         req);
847                 if (ret != LDB_SUCCESS) {
848                         return ret;
849                 }
850
851                 /* go on with the call chain */
852                 return ldb_next_request(module, down_req);
853         }
854
855         /* This isn't the default branch of the switch, but a 'in any
856          * other case'.  When a delete isn't for all objectClasses for
857          * example
858          */
859
860         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
861         if (msg == NULL) {
862                 ldb_oom(ldb);
863                 return LDB_ERR_OPERATIONS_ERROR;
864         }
865
866         ret = fix_check_attributes(ldb, schema, msg, req->operation);
867         if (ret != LDB_SUCCESS) {
868                 ldb_oom(ldb);
869                 return ret;
870         }
871
872         ret = ldb_build_mod_req(&down_req, ldb, ac,
873                                 msg,
874                                 req->controls,
875                                 ac, oc_modify_callback,
876                                 req);
877         if (ret != LDB_SUCCESS) {
878                 return ret;
879         }
880
881         return ldb_next_request(module, down_req);
882 }
883
884 static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
885 {
886         struct ldb_context *ldb;
887         static const char * const attrs[] = { "objectClass", NULL };
888         struct ldb_request *search_req;
889         struct oc_context *ac;
890         int ret;
891
892         ac = talloc_get_type(req->context, struct oc_context);
893         ldb = ldb_module_get_ctx(ac->module);
894
895         if (!ares) {
896                 return ldb_module_done(ac->req, NULL, NULL,
897                                         LDB_ERR_OPERATIONS_ERROR);
898         }
899
900         if (ares->type == LDB_REPLY_REFERRAL) {
901                 return ldb_module_send_referral(ac->req, ares->referral);
902         }
903
904         if (ares->error != LDB_SUCCESS) {
905                 return ldb_module_done(ac->req, ares->controls,
906                                         ares->response, ares->error);
907         }
908
909         if (ares->type != LDB_REPLY_DONE) {
910                 talloc_free(ares);
911                 return ldb_module_done(ac->req, NULL, NULL,
912                                         LDB_ERR_OPERATIONS_ERROR);
913         }
914
915         talloc_free(ares);
916
917         ret = ldb_build_search_req(&search_req, ldb, ac,
918                                    ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
919                                    "(objectClass=*)",
920                                    attrs, NULL, 
921                                    ac, get_search_callback,
922                                    ac->req);
923         if (ret != LDB_SUCCESS) {
924                 return ldb_module_done(ac->req, NULL, NULL, ret);
925         }
926
927         ac->step_fn = objectclass_do_mod;
928
929         ret = ldb_next_request(ac->module, search_req);
930         if (ret != LDB_SUCCESS) {
931                 return ldb_module_done(ac->req, NULL, NULL, ret);
932         }
933         return LDB_SUCCESS;
934 }
935
936 static int objectclass_do_mod(struct oc_context *ac)
937 {
938         struct ldb_context *ldb;
939         const struct dsdb_schema *schema;
940         struct ldb_request *mod_req;
941         char *value;
942         struct ldb_message_element *objectclass_element;
943         struct ldb_message *msg;
944         TALLOC_CTX *mem_ctx;
945         struct class_list *sorted, *current;
946         int ret;
947
948         ldb = ldb_module_get_ctx(ac->module);
949
950         if (ac->search_res == NULL) {
951                 return LDB_ERR_OPERATIONS_ERROR;
952         }
953         schema = dsdb_get_schema(ldb, ac);
954
955         mem_ctx = talloc_new(ac);
956         if (mem_ctx == NULL) {
957                 return LDB_ERR_OPERATIONS_ERROR;
958         }
959
960         /* use a new message structure */
961         msg = ldb_msg_new(ac);
962         if (msg == NULL) {
963                 ldb_set_errstring(ldb,
964                         "objectclass: could not create new modify msg");
965                 talloc_free(mem_ctx);
966                 return LDB_ERR_OPERATIONS_ERROR;
967         }
968
969         /* This is now the objectClass list from the database */
970         objectclass_element = ldb_msg_find_element(ac->search_res->message, 
971                                                    "objectClass");
972         if (!objectclass_element) {
973                 /* Where did it go?  bail now... */
974                 talloc_free(mem_ctx);
975                 return LDB_ERR_OPERATIONS_ERROR;
976         }
977         
978         /* modify dn */
979         msg->dn = ac->req->op.mod.message->dn;
980
981         ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
982         if (ret != LDB_SUCCESS) {
983                 return ret;
984         }
985
986         /* We must completely replace the existing objectClass entry.
987          * We could do a constrained add/del, but we are meant to be
988          * in a transaction... */
989
990         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
991         if (ret != LDB_SUCCESS) {
992                 ldb_set_errstring(ldb, "objectclass: could not clear objectclass in modify msg");
993                 talloc_free(mem_ctx);
994                 return ret;
995         }
996         
997         /* Move from the linked list back into an ldb msg */
998         for (current = sorted; current; current = current->next) {
999                 value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
1000                 if (value == NULL) {
1001                         ldb_oom(ldb);
1002                         return LDB_ERR_OPERATIONS_ERROR;
1003                 }
1004                 ret = ldb_msg_add_string(msg, "objectClass", value);
1005                 if (ret != LDB_SUCCESS) {
1006                         ldb_set_errstring(ldb, "objectclass: could not re-add sorted objectclass to modify msg");
1007                         talloc_free(mem_ctx);
1008                         return ret;
1009                 }
1010         }
1011
1012         ret = ldb_msg_sanity_check(ldb, msg);
1013         if (ret != LDB_SUCCESS) {
1014                 talloc_free(mem_ctx);
1015                 return ret;
1016         }
1017
1018         ret = ldb_build_mod_req(&mod_req, ldb, ac,
1019                                 msg,
1020                                 ac->req->controls,
1021                                 ac, oc_op_callback,
1022                                 ac->req);
1023         if (ret != LDB_SUCCESS) {
1024                 talloc_free(mem_ctx);
1025                 return ret;
1026         }
1027
1028         talloc_free(mem_ctx);
1029         /* perform the modify */
1030         return ldb_next_request(ac->module, mod_req);
1031 }
1032
1033 static int objectclass_do_rename(struct oc_context *ac);
1034
1035 static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
1036 {
1037         static const char * const attrs[] = { NULL };
1038         struct ldb_context *ldb;
1039         struct ldb_request *search_req;
1040         struct oc_context *ac;
1041         struct ldb_dn *parent_dn;
1042         int ret;
1043
1044         ldb = ldb_module_get_ctx(module);
1045
1046         ldb_debug(ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
1047
1048         if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1049                 return ldb_next_request(module, req);
1050         }
1051
1052         /* Firstly ensure we are not trying to rename it to be a child of itself */
1053         if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0) 
1054             && (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
1055                 ldb_asprintf_errstring(ldb, "Cannot rename %s to be a child of itself",
1056                                        ldb_dn_get_linearized(req->op.rename.olddn));
1057                 return LDB_ERR_UNWILLING_TO_PERFORM;
1058         }
1059
1060         ac = oc_init_context(module, req);
1061         if (ac == NULL) {
1062                 return LDB_ERR_OPERATIONS_ERROR;
1063         }
1064
1065         parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
1066         if (parent_dn == NULL) {
1067                 ldb_oom(ldb);
1068                 return LDB_ERR_OPERATIONS_ERROR;
1069         }
1070
1071         /*
1072           it makes a search request, looking for the parent DN to fix up the new DN
1073           to a standard one, at objectclass_do_rename()
1074          */
1075         ret = ldb_build_search_req(&search_req, ldb,
1076                                    ac, parent_dn, LDB_SCOPE_BASE,
1077                                    "(objectClass=*)",
1078                                    attrs, NULL,
1079                                    ac, get_search_callback,
1080                                    req);
1081         if (ret != LDB_SUCCESS) {
1082                 return ret;
1083         }
1084
1085         /* we have to add the show deleted control, as otherwise DRS
1086            deletes will be refused as we will think the target parent
1087            does not exist */
1088         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, false, NULL);
1089
1090         if (ret != LDB_SUCCESS) {
1091                 return ret;
1092         }
1093
1094         ac->step_fn = objectclass_do_rename;
1095
1096         return ldb_next_request(ac->module, search_req);
1097
1098
1099 }
1100
1101 static int objectclass_do_rename(struct oc_context *ac)
1102 {
1103         struct ldb_context *ldb;
1104         struct ldb_request *rename_req;
1105         struct ldb_dn *fixed_dn;
1106         int ret;
1107
1108         ldb = ldb_module_get_ctx(ac->module);
1109
1110         /* Check we have a valid parent */
1111         if (ac->search_res == NULL) {
1112                 ldb_asprintf_errstring(ldb, "objectclass: Cannot rename %s, parent does not exist!", 
1113                                        ldb_dn_get_linearized(ac->req->op.rename.newdn));
1114                 return LDB_ERR_UNWILLING_TO_PERFORM;
1115         }
1116         
1117         /* Fix up the DN to be in the standard form,
1118          * taking particular care to match the parent DN */
1119         ret = fix_dn(ac,
1120                      ac->req->op.rename.newdn,
1121                      ac->search_res->message->dn,
1122                      &fixed_dn);
1123         if (ret != LDB_SUCCESS) {
1124                 return ret;
1125         }
1126
1127         /* TODO: Check this is a valid child to this parent,
1128          * by reading the allowedChildClasses and
1129          * allowedChildClasssesEffective attributes */
1130
1131         ret = ldb_build_rename_req(&rename_req, ldb, ac,
1132                                    ac->req->op.rename.olddn, fixed_dn,
1133                                    ac->req->controls,
1134                                    ac, oc_op_callback,
1135                                    ac->req);
1136         if (ret != LDB_SUCCESS) {
1137                 return ret;
1138         }
1139
1140         /* perform the rename */
1141         return ldb_next_request(ac->module, rename_req);
1142 }
1143
1144 static int objectclass_init(struct ldb_module *module)
1145 {
1146         struct ldb_context *ldb = ldb_module_get_ctx(module);
1147         int ret;
1148         /* Init everything else */
1149         ret = ldb_next_init(module);
1150         if (ret != LDB_SUCCESS) {
1151                 return ret;
1152         }
1153         
1154         /* Look for the opaque to indicate we might have to cut down the DN of defaultObjectCategory */
1155         ldb_module_set_private(module, ldb_get_opaque(ldb, DSDB_EXTENDED_DN_STORE_FORMAT_OPAQUE_NAME));
1156
1157         return ret;
1158 }
1159
1160 _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
1161         .name              = "objectclass",
1162         .add           = objectclass_add,
1163         .modify        = objectclass_modify,
1164         .rename        = objectclass_rename,
1165         .init_context  = objectclass_init
1166 };