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