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