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