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