s4:dsdb/schema_data: allow DSDB_CONTROL_SEC_DESC_PROPAGATION_OID on modify
[kai/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
148         ldb = ldb_module_get_ctx(module);
149
150         /* special objects should always go through */
151         if (ldb_dn_is_special(req->op.add.message->dn)) {
152                 return ldb_next_request(module, req);
153         }
154
155         /* replicated update should always go through */
156         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
157                 return ldb_next_request(module, req);
158         }
159
160         schema = dsdb_get_schema(ldb, req);
161         if (!schema) {
162                 return ldb_next_request(module, req);
163         }
164
165         if (schema->base_dn == NULL) {
166                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
167                           "schema_data_add: base_dn NULL\n");
168                 return LDB_ERR_OPERATIONS_ERROR;
169         }
170
171         ret = samdb_rodc(ldb, &rodc);
172         if (ret != LDB_SUCCESS) {
173                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
174         }
175
176         if (!schema->fsmo.we_are_master && !rodc) {
177                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
178                           "schema_data_add: we are not master: reject request\n");
179                 return LDB_ERR_UNWILLING_TO_PERFORM;
180         }
181
182         if (!schema->fsmo.update_allowed && !rodc) {
183                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
184                           "schema_data_add: updates are not allowed: reject request\n");
185                 return LDB_ERR_UNWILLING_TO_PERFORM;
186         }
187
188         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
189                 /*
190                  * the provision code needs to create
191                  * the schema root object.
192                  */
193                 cmp = ldb_dn_compare(req->op.add.message->dn, schema->base_dn);
194                 if (cmp == 0) {
195                         return ldb_next_request(module, req);
196                 }
197         }
198
199         parent_dn = ldb_dn_get_parent(req, req->op.add.message->dn);
200         if (!parent_dn) {
201                 return ldb_oom(ldb);
202         }
203
204         cmp = ldb_dn_compare(parent_dn, schema->base_dn);
205         if (cmp != 0) {
206                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
207                           "schema_data_add: no direct child :%s\n",
208                           ldb_dn_get_linearized(req->op.add.message->dn));
209                 return LDB_ERR_UNWILLING_TO_PERFORM;
210         }
211
212         attributeID = ldb_msg_find_ldb_val(req->op.add.message, "attributeID");
213         governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID");
214
215         if (attributeID) {
216                 oid_attr = "attributeID";
217                 oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length);
218         } else if (governsID) {
219                 oid_attr = "governsID";
220                 oid = talloc_strndup(req, (const char *)governsID->data, governsID->length);
221         } else {
222                 return ldb_next_request(module, req);
223         }
224
225         if (!oid) {
226                 return ldb_oom(ldb);
227         }
228
229         status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL);
230         if (!W_ERROR_IS_OK(status)) {
231                 /* check for internal errors */
232                 if (!W_ERROR_EQUAL(status, WERR_NOT_FOUND)) {
233                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
234                                       "schema_data_add: failed to map %s[%s]: %s\n",
235                                       oid_attr, oid, win_errstr(status));
236                         return LDB_ERR_UNWILLING_TO_PERFORM;
237                 }
238
239                 /* Update prefixMap and save it */
240                 status = dsdb_create_prefix_mapping(ldb, schema, oid);
241                 if (!W_ERROR_IS_OK(status)) {
242                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
243                                   "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n",
244                                   oid_attr, oid, win_errstr(status));
245                         return LDB_ERR_UNWILLING_TO_PERFORM;
246                 }
247         }
248
249         return ldb_next_request(module, req);
250 }
251
252 static int schema_data_modify(struct ldb_module *module, struct ldb_request *req)
253 {
254         struct ldb_context *ldb;
255         struct dsdb_schema *schema;
256         int cmp;
257         bool rodc = false;
258         int ret;
259         struct ldb_control *sd_propagation_control;
260
261         ldb = ldb_module_get_ctx(module);
262
263         /* special objects should always go through */
264         if (ldb_dn_is_special(req->op.mod.message->dn)) {
265                 return ldb_next_request(module, req);
266         }
267
268         /* replicated update should always go through */
269         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
270                 return ldb_next_request(module, req);
271         }
272
273         /* dbcheck should be able to fix things */
274         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
275                 return ldb_next_request(module, req);
276         }
277
278         sd_propagation_control = ldb_request_get_control(req,
279                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
280         if (sd_propagation_control != NULL) {
281                 if (req->op.mod.message->num_elements != 1) {
282                         return ldb_module_operr(module);
283                 }
284                 ret = strcmp(req->op.mod.message->elements[0].name,
285                              "nTSecurityDescriptor");
286                 if (ret != 0) {
287                         return ldb_module_operr(module);
288                 }
289
290                 return ldb_next_request(module, req);
291         }
292
293         schema = dsdb_get_schema(ldb, req);
294         if (!schema) {
295                 return ldb_next_request(module, req);
296         }
297
298         cmp = ldb_dn_compare(req->op.mod.message->dn, schema->base_dn);
299         if (cmp == 0) {
300                 static const char * const constrained_attrs[] = {
301                         "schemaInfo",
302                         "prefixMap",
303                         "msDs-Schema-Extensions",
304                         "msDS-IntId",
305                         NULL
306                 };
307                 size_t i;
308                 struct ldb_message_element *el;
309
310                 if (ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID)) {
311                         return ldb_next_request(module, req);
312                 }
313
314                 for (i=0; constrained_attrs[i]; i++) {
315                         el = ldb_msg_find_element(req->op.mod.message,
316                                                   constrained_attrs[i]);
317                         if (el == NULL) {
318                                 continue;
319                         }
320
321                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
322                                       "schema_data_modify: reject update "
323                                       "of attribute[%s]\n",
324                                       constrained_attrs[i]);
325                         return LDB_ERR_CONSTRAINT_VIOLATION;
326                 }
327
328                 return ldb_next_request(module, req);
329         }
330
331         ret = samdb_rodc(ldb, &rodc);
332         if (ret != LDB_SUCCESS) {
333                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
334         }
335
336         if (!schema->fsmo.we_are_master && !rodc) {
337                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
338                           "schema_data_modify: we are not master: reject request\n");
339                 return LDB_ERR_UNWILLING_TO_PERFORM;
340         }
341
342         if (!schema->fsmo.update_allowed && !rodc) {
343                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
344                           "schema_data_modify: updates are not allowed: reject request\n");
345                 return LDB_ERR_UNWILLING_TO_PERFORM;
346         }
347
348         return ldb_next_request(module, req);
349 }
350
351 static int schema_data_del(struct ldb_module *module, struct ldb_request *req)
352 {
353         struct ldb_context *ldb;
354         struct dsdb_schema *schema;
355         bool rodc = false;
356         int ret;
357
358         ldb = ldb_module_get_ctx(module);
359
360         /* special objects should always go through */
361         if (ldb_dn_is_special(req->op.del.dn)) {
362                 return ldb_next_request(module, req);
363         }
364
365         /* replicated update should always go through */
366         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
367                 return ldb_next_request(module, req);
368         }
369
370         /* dbcheck should be able to fix things */
371         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
372                 return ldb_next_request(module, req);
373         }
374
375         schema = dsdb_get_schema(ldb, req);
376         if (!schema) {
377                 return ldb_next_request(module, req);
378         }
379
380         ret = samdb_rodc(ldb, &rodc);
381         if (ret != LDB_SUCCESS) {
382                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
383         }
384
385         if (!schema->fsmo.we_are_master && !rodc) {
386                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
387                           "schema_data_modify: we are not master: reject request\n");
388                 return LDB_ERR_UNWILLING_TO_PERFORM;
389         }
390
391         /*
392          * normaly the DACL will prevent delete
393          * with LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
394          * above us.
395          */
396         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
397                       "schema_data_del: delete is not allowed in the schema\n");
398         return LDB_ERR_UNWILLING_TO_PERFORM;
399 }
400
401 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
402                                   const struct dsdb_schema *schema) 
403 {
404         const struct dsdb_class *sclass;
405         int ret;
406
407         for (sclass = schema->classes; sclass; sclass = sclass->next) {
408                 ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass));
409                 if (ret != LDB_SUCCESS) {
410                         return ret;
411                 }
412         }
413         return LDB_SUCCESS;
414 }
415 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
416                                   const struct dsdb_schema *schema) 
417 {
418         const struct dsdb_attribute *attribute;
419         int ret;
420         
421         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
422                 ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
423                 if (ret != LDB_SUCCESS) {
424                         return ret;
425                 }
426         }
427         return LDB_SUCCESS;
428 }
429
430 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
431                                     const struct dsdb_schema *schema) 
432 {
433         const struct dsdb_class *sclass;
434         int ret;
435
436         for (sclass = schema->classes; sclass; sclass = sclass->next) {
437                 if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) {
438                         char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema);
439                         if (!ditcontentrule) {
440                                 return ldb_oom(ldb);
441                         }
442                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
443                         if (ret != LDB_SUCCESS) {
444                                 return ret;
445                         }
446                 }
447         }
448         return LDB_SUCCESS;
449 }
450
451 static int generate_extendedAttributeInfo(struct ldb_context *ldb,
452                                           struct ldb_message *msg,
453                                           const struct dsdb_schema *schema)
454 {
455         const struct dsdb_attribute *attribute;
456         int ret;
457
458         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
459                 char *val = schema_attribute_to_extendedInfo(msg, attribute);
460                 if (!val) {
461                         return ldb_oom(ldb);
462                 }
463
464                 ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val);
465                 if (ret != LDB_SUCCESS) {
466                         return ret;
467                 }
468         }
469
470         return LDB_SUCCESS;
471 }
472
473 static int generate_extendedClassInfo(struct ldb_context *ldb,
474                                       struct ldb_message *msg,
475                                       const struct dsdb_schema *schema)
476 {
477         const struct dsdb_class *sclass;
478         int ret;
479
480         for (sclass = schema->classes; sclass; sclass = sclass->next) {
481                 char *val = schema_class_to_extendedInfo(msg, sclass);
482                 if (!val) {
483                         return ldb_oom(ldb);
484                 }
485
486                 ret = ldb_msg_add_string(msg, "extendedClassInfo", val);
487                 if (ret != LDB_SUCCESS) {
488                         return ret;
489                 }
490         }
491
492         return LDB_SUCCESS;
493 }
494
495
496 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
497                                       const struct dsdb_schema *schema) 
498 {
499         struct ldb_dn *dn = msg->dn;
500         unsigned int i;
501         int ret;
502         const char *first_component_name = ldb_dn_get_component_name(dn, 0);
503         const struct ldb_val *first_component_val;
504         const struct dsdb_class *schema_class;
505         const char **possibleInferiors;
506
507         if (strcasecmp(first_component_name, "cn") != 0) {
508                 return LDB_SUCCESS;
509         }
510
511         first_component_val = ldb_dn_get_component_val(dn, 0);
512
513         schema_class = dsdb_class_by_cn_ldb_val(schema, first_component_val);
514         if (schema_class == NULL) {
515                 return LDB_SUCCESS;
516         }
517         
518         possibleInferiors = schema_class->possibleInferiors;
519         if (possibleInferiors == NULL) {
520                 return LDB_SUCCESS;
521         }
522
523         for (i=0;possibleInferiors[i];i++) {
524                 ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]);
525                 if (ret != LDB_SUCCESS) {
526                         return ret;
527                 }
528         }
529
530         return LDB_SUCCESS;
531 }
532
533
534 /* Add objectClasses, attributeTypes and dITContentRules from the
535    schema object (they are not stored in the database)
536  */
537 static int schema_data_search_callback(struct ldb_request *req, struct ldb_reply *ares)
538 {
539         struct ldb_context *ldb;
540         struct schema_data_search_data *ac;
541         struct schema_data_private_data *mc;
542         unsigned int i;
543         int ret;
544
545         ac = talloc_get_type(req->context, struct schema_data_search_data);
546         mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_data_private_data);
547         ldb = ldb_module_get_ctx(ac->module);
548
549         if (!ares) {
550                 return ldb_module_done(ac->req, NULL, NULL,
551                                         LDB_ERR_OPERATIONS_ERROR);
552         }
553         if (ares->error != LDB_SUCCESS) {
554                 return ldb_module_done(ac->req, ares->controls,
555                                         ares->response, ares->error);
556         }
557         /* Only entries are interesting, and we handle the case of the parent seperatly */
558
559         switch (ares->type) {
560         case LDB_REPLY_ENTRY:
561
562                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) {
563                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
564                                 if (generated_attrs[i].aggregate &&
565                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
566                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
567                                         if (ret != LDB_SUCCESS) {
568                                                 return ret;
569                                         }
570                                 }
571                         }
572                 } else if ((ldb_dn_compare_base(mc->schema_dn, ares->message->dn) == 0)
573                            && (ldb_dn_compare(mc->schema_dn, ares->message->dn) != 0)) {
574                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
575                                 if (!generated_attrs[i].aggregate &&
576                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
577                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
578                                         if (ret != LDB_SUCCESS) {
579                                                 return ret;
580                                         }
581                                 }
582                         }
583                 }
584
585
586                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
587
588         case LDB_REPLY_REFERRAL:
589
590                 return ldb_module_send_referral(ac->req, ares->referral);
591
592         case LDB_REPLY_DONE:
593
594                 return ldb_module_done(ac->req, ares->controls,
595                                         ares->response, ares->error);
596         }
597
598         return LDB_SUCCESS;
599 }
600
601 /* search */
602 static int schema_data_search(struct ldb_module *module, struct ldb_request *req)
603 {
604         struct ldb_context *ldb = ldb_module_get_ctx(module);
605         unsigned int i;
606         int ret;
607         struct schema_data_search_data *search_context;
608         struct ldb_request *down_req;
609         const struct dsdb_schema *schema;
610         if (!ldb_module_get_private(module)) {
611                 /* If there is no module data, there is little we can do */
612                 return ldb_next_request(module, req);
613         }
614
615         /* The schema manipulation does not apply to special DNs */
616         if (ldb_dn_is_special(req->op.search.base)) {
617                 return ldb_next_request(module, req);
618         }
619
620         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
621                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
622                         break;
623                 }
624         }
625         if (i == ARRAY_SIZE(generated_attrs)) {
626                 /* No request for a generated attr found, nothing to
627                  * see here, move along... */
628                 return ldb_next_request(module, req);
629         }
630
631         schema = dsdb_get_schema(ldb, NULL);
632         if (!schema || !ldb_module_get_private(module)) {
633                 /* If there is no schema, there is little we can do */
634                 return ldb_next_request(module, req);
635         }
636
637         search_context = talloc(req, struct schema_data_search_data);
638         if (!search_context) {
639                 return ldb_oom(ldb);
640         }
641
642         search_context->module = module;
643         search_context->req = req;
644         search_context->schema = talloc_reference(search_context, schema);
645         if (!search_context->schema) {
646                 return ldb_oom(ldb);
647         }
648
649         ret = ldb_build_search_req_ex(&down_req, ldb, search_context,
650                                         req->op.search.base,
651                                         req->op.search.scope,
652                                         req->op.search.tree,
653                                         req->op.search.attrs,
654                                         req->controls,
655                                         search_context, schema_data_search_callback,
656                                         req);
657         LDB_REQ_SET_LOCATION(down_req);
658         if (ret != LDB_SUCCESS) {
659                 return ldb_operr(ldb);
660         }
661
662         return ldb_next_request(module, down_req);
663 }
664
665
666 static const struct ldb_module_ops ldb_schema_data_module_ops = {
667         .name           = "schema_data",
668         .init_context   = schema_data_init,
669         .add            = schema_data_add,
670         .modify         = schema_data_modify,
671         .del            = schema_data_del,
672         .search         = schema_data_search
673 };
674
675 int ldb_schema_data_module_init(const char *version)
676 {
677         LDB_MODULE_CHECK_VERSION(version);
678         return ldb_register_module(&ldb_schema_data_module_ops);
679 }