dsdb partition.c: Make partition_copy_all aysnc.
[samba.git] / source4 / dsdb / samdb / ldb_modules / schema_data.c
1 /* 
2    Unix SMB/CIFS mplementation.
3
4    The module that handles the Schema checkings and dynamic attributes
5    
6    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
8     
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21    
22 */
23
24 #include "includes.h"
25 #include "ldb_module.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_drsuapi.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30 #include "param/param.h"
31 #include "dsdb/samdb/ldb_modules/util.h"
32
33 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
34                                   const struct dsdb_schema *schema);
35 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
36                                    const struct dsdb_schema *schema);
37 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
38                                     const struct dsdb_schema *schema);
39 static int generate_extendedAttributeInfo(struct ldb_context *ldb, struct ldb_message *msg,
40                                           const struct dsdb_schema *schema);
41 static int generate_extendedClassInfo(struct ldb_context *ldb, struct ldb_message *msg,
42                                       const struct dsdb_schema *schema);
43 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
44                                       const struct dsdb_schema *schema);
45
46 static const struct {
47         const char *attr;
48         int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *);
49         bool aggregate;
50 } generated_attrs[] = {
51         {
52                 .attr = "objectClasses",
53                 .fn = generate_objectClasses,
54                 .aggregate = true,
55         },
56         {
57                 .attr = "attributeTypes",
58                 .fn = generate_attributeTypes,
59                 .aggregate = true,
60         },
61         {
62                 .attr = "dITContentRules",
63                 .fn = generate_dITContentRules,
64                 .aggregate = true,
65         },
66         {
67                 .attr = "extendedAttributeInfo",
68                 .fn = generate_extendedAttributeInfo,
69                 .aggregate = true,
70         },
71         {
72                 .attr = "extendedClassInfo",
73                 .fn = generate_extendedClassInfo,
74                 .aggregate = true,
75         },
76         {
77                 .attr = "possibleInferiors",
78                 .fn = generate_possibleInferiors,
79                 .aggregate = false,
80         }
81 };
82
83 struct schema_data_private_data {
84         struct ldb_dn *aggregate_dn;
85         struct ldb_dn *schema_dn;
86 };
87
88 struct schema_data_search_data {
89         struct ldb_module *module;
90         struct ldb_request *req;
91
92         const struct dsdb_schema *schema;
93 };
94
95 static int schema_data_init(struct ldb_module *module)
96 {
97         struct ldb_context *ldb;
98         struct ldb_dn *schema_dn;
99         int ret;
100         struct schema_data_private_data *data;
101
102         ret = ldb_next_init(module);
103         if (ret != LDB_SUCCESS) {
104                 return ret;
105         }
106
107         ldb = ldb_module_get_ctx(module);
108         schema_dn = ldb_get_schema_basedn(ldb);
109         if (!schema_dn) {
110                 ldb_reset_err_string(ldb);
111                 ldb_debug(ldb, LDB_DEBUG_WARNING,
112                           "schema_data_init: no schema dn present: (skip schema loading)\n");
113                 return LDB_SUCCESS;
114         }
115
116         data = talloc(module, struct schema_data_private_data);
117         if (data == NULL) {
118                 return ldb_oom(ldb);
119         }
120
121         data->schema_dn = schema_dn;
122
123         /* Used to check to see if this is a result on the CN=Aggregate schema */
124         data->aggregate_dn = samdb_aggregate_schema_dn(ldb, data);
125         if (!data->aggregate_dn) {
126                 ldb_asprintf_errstring(ldb, "schema_data_init: Could not build aggregate schema DN for schema in %s", ldb_dn_get_linearized(schema_dn));
127                 return LDB_ERR_OPERATIONS_ERROR;
128         }
129
130         ldb_module_set_private(module, data);
131         return LDB_SUCCESS;
132 }
133
134 static int schema_data_add(struct ldb_module *module, struct ldb_request *req)
135 {
136         struct ldb_context *ldb;
137         struct dsdb_schema *schema;
138         const struct ldb_val *attributeID = NULL;
139         const struct ldb_val *governsID = NULL;
140         const char *oid_attr = NULL;
141         const char *oid = NULL;
142         struct ldb_dn *parent_dn = NULL;
143         int cmp;
144         WERROR status;
145         bool rodc = false;
146         int ret;
147         struct schema_data_private_data *mc;
148         mc = talloc_get_type(ldb_module_get_private(module), struct schema_data_private_data);
149
150         ldb = ldb_module_get_ctx(module);
151
152         /* special objects should always go through */
153         if (ldb_dn_is_special(req->op.add.message->dn)) {
154                 return ldb_next_request(module, req);
155         }
156
157         /* replicated update should always go through */
158         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
159                 return ldb_next_request(module, req);
160         }
161
162         schema = dsdb_get_schema(ldb, req);
163         if (!schema) {
164                 return ldb_next_request(module, req);
165         }
166
167         ret = samdb_rodc(ldb, &rodc);
168         if (ret != LDB_SUCCESS) {
169                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
170         }
171
172         if (!schema->fsmo.we_are_master && !rodc) {
173                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
174                           "schema_data_add: we are not master: reject add request\n");
175                 return LDB_ERR_UNWILLING_TO_PERFORM;
176         }
177
178         if (!schema->fsmo.update_allowed && !rodc) {
179                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
180                           "schema_data_add: updates are not allowed: reject add request\n");
181                 return LDB_ERR_UNWILLING_TO_PERFORM;
182         }
183
184         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
185                 /*
186                  * the provision code needs to create
187                  * the schema root object.
188                  */
189                 cmp = ldb_dn_compare(req->op.add.message->dn, mc->schema_dn);
190                 if (cmp == 0) {
191                         return ldb_next_request(module, req);
192                 }
193         }
194
195         parent_dn = ldb_dn_get_parent(req, req->op.add.message->dn);
196         if (!parent_dn) {
197                 return ldb_oom(ldb);
198         }
199
200         cmp = ldb_dn_compare(parent_dn, mc->schema_dn);
201         if (cmp != 0) {
202                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
203                           "schema_data_add: no direct child :%s\n",
204                           ldb_dn_get_linearized(req->op.add.message->dn));
205                 return LDB_ERR_UNWILLING_TO_PERFORM;
206         }
207
208         attributeID = ldb_msg_find_ldb_val(req->op.add.message, "attributeID");
209         governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID");
210
211         if (attributeID) {
212                 oid_attr = "attributeID";
213                 oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length);
214         } else if (governsID) {
215                 oid_attr = "governsID";
216                 oid = talloc_strndup(req, (const char *)governsID->data, governsID->length);
217         } else {
218                 return ldb_next_request(module, req);
219         }
220
221         if (!oid) {
222                 return ldb_oom(ldb);
223         }
224
225         status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL);
226         if (!W_ERROR_IS_OK(status)) {
227                 /* check for internal errors */
228                 if (!W_ERROR_EQUAL(status, WERR_NOT_FOUND)) {
229                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
230                                       "schema_data_add: failed to map %s[%s]: %s\n",
231                                       oid_attr, oid, win_errstr(status));
232                         return LDB_ERR_UNWILLING_TO_PERFORM;
233                 }
234
235                 /* Update prefixMap and save it */
236                 status = dsdb_create_prefix_mapping(ldb, schema, oid);
237                 if (!W_ERROR_IS_OK(status)) {
238                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
239                                   "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n",
240                                   oid_attr, oid, win_errstr(status));
241                         return LDB_ERR_UNWILLING_TO_PERFORM;
242                 }
243         }
244
245         return ldb_next_request(module, req);
246 }
247
248 static int schema_data_modify(struct ldb_module *module, struct ldb_request *req)
249 {
250         struct ldb_context *ldb;
251         struct dsdb_schema *schema;
252         int cmp;
253         bool rodc = false;
254         int ret;
255         struct ldb_control *sd_propagation_control;
256         struct schema_data_private_data *mc;
257         mc = talloc_get_type(ldb_module_get_private(module), struct schema_data_private_data);
258
259         ldb = ldb_module_get_ctx(module);
260
261         /* special objects should always go through */
262         if (ldb_dn_is_special(req->op.mod.message->dn)) {
263                 return ldb_next_request(module, req);
264         }
265
266         /* replicated update should always go through */
267         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
268                 return ldb_next_request(module, req);
269         }
270
271         /* dbcheck should be able to fix things */
272         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
273                 return ldb_next_request(module, req);
274         }
275
276         sd_propagation_control = ldb_request_get_control(req,
277                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
278         if (sd_propagation_control != NULL) {
279                 if (req->op.mod.message->num_elements != 1) {
280                         return ldb_module_operr(module);
281                 }
282                 ret = strcmp(req->op.mod.message->elements[0].name,
283                              "nTSecurityDescriptor");
284                 if (ret != 0) {
285                         return ldb_module_operr(module);
286                 }
287
288                 return ldb_next_request(module, req);
289         }
290
291         schema = dsdb_get_schema(ldb, req);
292         if (!schema) {
293                 return ldb_next_request(module, req);
294         }
295
296         cmp = ldb_dn_compare(req->op.mod.message->dn, mc->schema_dn);
297         if (cmp == 0) {
298                 static const char * const constrained_attrs[] = {
299                         "schemaInfo",
300                         "prefixMap",
301                         "msDs-Schema-Extensions",
302                         "msDS-IntId",
303                         NULL
304                 };
305                 size_t i;
306                 struct ldb_message_element *el;
307
308                 if (ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID)) {
309                         return ldb_next_request(module, req);
310                 }
311
312                 for (i=0; constrained_attrs[i]; i++) {
313                         el = ldb_msg_find_element(req->op.mod.message,
314                                                   constrained_attrs[i]);
315                         if (el == NULL) {
316                                 continue;
317                         }
318
319                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
320                                       "schema_data_modify: reject update "
321                                       "of attribute[%s]\n",
322                                       constrained_attrs[i]);
323                         return LDB_ERR_CONSTRAINT_VIOLATION;
324                 }
325
326                 return ldb_next_request(module, req);
327         }
328
329         ret = samdb_rodc(ldb, &rodc);
330         if (ret != LDB_SUCCESS) {
331                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
332         }
333
334         if (!schema->fsmo.we_are_master && !rodc) {
335                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
336                           "schema_data_modify: we are not master: reject modify request\n");
337                 return LDB_ERR_UNWILLING_TO_PERFORM;
338         }
339
340         if (!schema->fsmo.update_allowed && !rodc) {
341                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
342                           "schema_data_modify: updates are not allowed: reject modify request\n");
343                 return LDB_ERR_UNWILLING_TO_PERFORM;
344         }
345
346         return ldb_next_request(module, req);
347 }
348
349 static int schema_data_del(struct ldb_module *module, struct ldb_request *req)
350 {
351         struct ldb_context *ldb;
352         struct dsdb_schema *schema;
353         bool rodc = false;
354         int ret;
355
356         ldb = ldb_module_get_ctx(module);
357
358         /* special objects should always go through */
359         if (ldb_dn_is_special(req->op.del.dn)) {
360                 return ldb_next_request(module, req);
361         }
362
363         /* replicated update should always go through */
364         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
365                 return ldb_next_request(module, req);
366         }
367
368         /* dbcheck should be able to fix things */
369         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
370                 return ldb_next_request(module, req);
371         }
372
373         schema = dsdb_get_schema(ldb, req);
374         if (!schema) {
375                 return ldb_next_request(module, req);
376         }
377
378         ret = samdb_rodc(ldb, &rodc);
379         if (ret != LDB_SUCCESS) {
380                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
381         }
382
383         if (!schema->fsmo.we_are_master && !rodc) {
384                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
385                           "schema_data_modify: we are not master: reject request\n");
386                 return LDB_ERR_UNWILLING_TO_PERFORM;
387         }
388
389         /*
390          * normaly the DACL will prevent delete
391          * with LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
392          * above us.
393          */
394         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
395                       "schema_data_del: delete is not allowed in the schema\n");
396         return LDB_ERR_UNWILLING_TO_PERFORM;
397 }
398
399 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
400                                   const struct dsdb_schema *schema) 
401 {
402         const struct dsdb_class *sclass;
403         int ret;
404
405         for (sclass = schema->classes; sclass; sclass = sclass->next) {
406                 char *v = schema_class_to_description(msg, sclass);
407                 if (v == NULL) {
408                         return ldb_oom(ldb);
409                 }
410                 ret = ldb_msg_add_steal_string(msg, "objectClasses", v);
411                 if (ret != LDB_SUCCESS) {
412                         return ret;
413                 }
414         }
415         return LDB_SUCCESS;
416 }
417 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
418                                   const struct dsdb_schema *schema) 
419 {
420         const struct dsdb_attribute *attribute;
421         int ret;
422
423         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
424                 char *v = schema_attribute_to_description(msg, attribute);
425                 if (v == NULL) {
426                         return ldb_oom(ldb);
427                 }
428                 ret = ldb_msg_add_steal_string(msg, "attributeTypes", v);
429                 if (ret != LDB_SUCCESS) {
430                         return ret;
431                 }
432         }
433         return LDB_SUCCESS;
434 }
435
436 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
437                                     const struct dsdb_schema *schema) 
438 {
439         const struct dsdb_class *sclass;
440         int ret;
441
442         for (sclass = schema->classes; sclass; sclass = sclass->next) {
443                 if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) {
444                         char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema);
445                         if (!ditcontentrule) {
446                                 return ldb_oom(ldb);
447                         }
448                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
449                         if (ret != LDB_SUCCESS) {
450                                 return ret;
451                         }
452                 }
453         }
454         return LDB_SUCCESS;
455 }
456
457 static int generate_extendedAttributeInfo(struct ldb_context *ldb,
458                                           struct ldb_message *msg,
459                                           const struct dsdb_schema *schema)
460 {
461         const struct dsdb_attribute *attribute;
462         int ret;
463
464         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
465                 char *val = schema_attribute_to_extendedInfo(msg, attribute);
466                 if (!val) {
467                         return ldb_oom(ldb);
468                 }
469
470                 ret = ldb_msg_add_steal_string(msg, "extendedAttributeInfo", val);
471                 if (ret != LDB_SUCCESS) {
472                         return ret;
473                 }
474         }
475
476         return LDB_SUCCESS;
477 }
478
479 static int generate_extendedClassInfo(struct ldb_context *ldb,
480                                       struct ldb_message *msg,
481                                       const struct dsdb_schema *schema)
482 {
483         const struct dsdb_class *sclass;
484         int ret;
485
486         for (sclass = schema->classes; sclass; sclass = sclass->next) {
487                 char *val = schema_class_to_extendedInfo(msg, sclass);
488                 if (!val) {
489                         return ldb_oom(ldb);
490                 }
491
492                 ret = ldb_msg_add_steal_string(msg, "extendedClassInfo", val);
493                 if (ret != LDB_SUCCESS) {
494                         return ret;
495                 }
496         }
497
498         return LDB_SUCCESS;
499 }
500
501
502 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
503                                       const struct dsdb_schema *schema) 
504 {
505         struct ldb_dn *dn = msg->dn;
506         unsigned int i;
507         int ret;
508         const char *first_component_name = ldb_dn_get_component_name(dn, 0);
509         const struct ldb_val *first_component_val;
510         const struct dsdb_class *schema_class;
511         const char **possibleInferiors;
512
513         if (strcasecmp(first_component_name, "cn") != 0) {
514                 return LDB_SUCCESS;
515         }
516
517         first_component_val = ldb_dn_get_component_val(dn, 0);
518
519         schema_class = dsdb_class_by_cn_ldb_val(schema, first_component_val);
520         if (schema_class == NULL) {
521                 return LDB_SUCCESS;
522         }
523         
524         possibleInferiors = schema_class->possibleInferiors;
525         if (possibleInferiors == NULL) {
526                 return LDB_SUCCESS;
527         }
528
529         for (i=0;possibleInferiors[i];i++) {
530                 char *v = talloc_strdup(msg, possibleInferiors[i]);
531                 if (v == NULL) {
532                         return ldb_oom(ldb);
533                 }
534                 ret = ldb_msg_add_steal_string(msg, "possibleInferiors", v);
535                 if (ret != LDB_SUCCESS) {
536                         return ret;
537                 }
538         }
539
540         return LDB_SUCCESS;
541 }
542
543
544 /* Add objectClasses, attributeTypes and dITContentRules from the
545    schema object (they are not stored in the database)
546  */
547 static int schema_data_search_callback(struct ldb_request *req, struct ldb_reply *ares)
548 {
549         struct ldb_context *ldb;
550         struct schema_data_search_data *ac;
551         struct schema_data_private_data *mc;
552         unsigned int i;
553         int ret;
554
555         ac = talloc_get_type(req->context, struct schema_data_search_data);
556         mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_data_private_data);
557         ldb = ldb_module_get_ctx(ac->module);
558
559         if (!ares) {
560                 return ldb_module_done(ac->req, NULL, NULL,
561                                         LDB_ERR_OPERATIONS_ERROR);
562         }
563         if (ares->error != LDB_SUCCESS) {
564                 return ldb_module_done(ac->req, ares->controls,
565                                         ares->response, ares->error);
566         }
567         /* Only entries are interesting, and we handle the case of the parent seperatly */
568
569         switch (ares->type) {
570         case LDB_REPLY_ENTRY:
571
572                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) {
573                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
574                                 if (generated_attrs[i].aggregate &&
575                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
576                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
577                                         if (ret != LDB_SUCCESS) {
578                                                 return ret;
579                                         }
580                                 }
581                         }
582                 } else if ((ldb_dn_compare_base(mc->schema_dn, ares->message->dn) == 0)
583                            && (ldb_dn_compare(mc->schema_dn, ares->message->dn) != 0)) {
584                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
585                                 if (!generated_attrs[i].aggregate &&
586                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
587                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
588                                         if (ret != LDB_SUCCESS) {
589                                                 return ret;
590                                         }
591                                 }
592                         }
593                 }
594
595
596                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
597
598         case LDB_REPLY_REFERRAL:
599
600                 return ldb_module_send_referral(ac->req, ares->referral);
601
602         case LDB_REPLY_DONE:
603
604                 return ldb_module_done(ac->req, ares->controls,
605                                         ares->response, ares->error);
606         }
607
608         return LDB_SUCCESS;
609 }
610
611 /* search */
612 static int schema_data_search(struct ldb_module *module, struct ldb_request *req)
613 {
614         struct ldb_context *ldb = ldb_module_get_ctx(module);
615         unsigned int i;
616         int ret;
617         struct schema_data_search_data *search_context;
618         struct ldb_request *down_req;
619         const struct dsdb_schema *schema;
620         if (!ldb_module_get_private(module)) {
621                 /* If there is no module data, there is little we can do */
622                 return ldb_next_request(module, req);
623         }
624
625         /* The schema manipulation does not apply to special DNs */
626         if (ldb_dn_is_special(req->op.search.base)) {
627                 return ldb_next_request(module, req);
628         }
629
630         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
631                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
632                         break;
633                 }
634         }
635         if (i == ARRAY_SIZE(generated_attrs)) {
636                 /* No request for a generated attr found, nothing to
637                  * see here, move along... */
638                 return ldb_next_request(module, req);
639         }
640
641         schema = dsdb_get_schema(ldb, NULL);
642         if (!schema || !ldb_module_get_private(module)) {
643                 /* If there is no schema, there is little we can do */
644                 return ldb_next_request(module, req);
645         }
646
647         search_context = talloc(req, struct schema_data_search_data);
648         if (!search_context) {
649                 return ldb_oom(ldb);
650         }
651
652         search_context->module = module;
653         search_context->req = req;
654         search_context->schema = talloc_reference(search_context, schema);
655         if (!search_context->schema) {
656                 return ldb_oom(ldb);
657         }
658
659         ret = ldb_build_search_req_ex(&down_req, ldb, search_context,
660                                         req->op.search.base,
661                                         req->op.search.scope,
662                                         req->op.search.tree,
663                                         req->op.search.attrs,
664                                         req->controls,
665                                         search_context, schema_data_search_callback,
666                                         req);
667         LDB_REQ_SET_LOCATION(down_req);
668         if (ret != LDB_SUCCESS) {
669                 return ldb_operr(ldb);
670         }
671
672         return ldb_next_request(module, down_req);
673 }
674
675
676 static const struct ldb_module_ops ldb_schema_data_module_ops = {
677         .name           = "schema_data",
678         .init_context   = schema_data_init,
679         .add            = schema_data_add,
680         .modify         = schema_data_modify,
681         .del            = schema_data_del,
682         .search         = schema_data_search
683 };
684
685 int ldb_schema_data_module_init(const char *version)
686 {
687         LDB_MODULE_CHECK_VERSION(version);
688         return ldb_register_module(&ldb_schema_data_module_ops);
689 }