1 /*
2    ldb database library
3 
4    Copyright (C) Simo Sorce  2004-2006
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 /*
22  *  Name: ldb
23  *
24  *  Component: ldb schema module
25  *
26  *  Description: add schema check functionality
27  *
28  *  Author: Simo Sorce
29  *
30  *  License: GNU GPL v2 or Later
31  */
32 
33 #include "includes.h"
34 #include "libcli/ldap/ldap.h"
35 #include "ldb/include/ldb_errors.h"
36 #include "ldb/include/ldb_private.h"
37 #include "lib/util/dlinklist.h"
38 #include "schema_syntax.h"
39 
40 /* Syntax-Table
41 
42    see ldap_server/devdocs/AD-syntaxes.txt
43 */
44 
45 enum schema_class_type {
46 	SCHEMA_CT_88		= 0,
47 	SCHEMA_CT_STRUCTURAL	= 1,
48 	SCHEMA_CT_ABSTRACT	= 2,
49 	SCHEMA_CT_AUXILIARY	= 3
50 };
51 
52 struct schema_attribute {
53 	char *OID;				/* attributeID     */
54 	char *name;				/* lDAPDisplayName */
55 	enum schema_internal_syntax syntax;	/* generated from attributeSyntax, oMSyntax, oMObjectClass */
56 	bool single;				/* isSingleValued  */
57 	int min;				/* rangeLower      */
58 	int max;				/* rangeUpper      */
59 	int systemflag;				/* systemFlag      */
60 	int searchflag;				/* searchFlag      */
61 	bool isdefunct;				/* isDefunct       */
62 };
63 
64 struct schema_class {
65 	char *OID;				/* governsID             */
66 	char *name;				/* lDAPDisplayName       */
67 	enum schema_class_type type;		/* objectClassCategory   */
68 	bool systemOnly;			/* systemOnly            */
69 	bool isdefunct;				/* isDefunct             */
70 	int systemflag;				/* systemFlag            */
71 	char *defobjcat;			/* defaultObjectCategory */
72 	struct schema_class *parent;		/* subClassOf            */
73 	struct schema_class **sysaux;		/* systemAuxiliaryClass  */
74 	struct schema_class **aux;		/* auxiliaryClass        */
75 	struct schema_class **sysposssup;	/* systemPossSuperiors   */
76 	struct schema_class **posssup;		/* possSuperiors         */
77 	struct schema_class **possinf;		/* possibleInferiors     */
78 	struct schema_attribute **sysmust;	/* systemMustContain     */
79 	struct schema_attribute **must;		/* MustContain           */
80 	struct schema_attribute **sysmay;	/* systemMayContain      */
81 	struct schema_attribute **may;		/* MayContain            */
82 };
83 
84 /* TODO: ditcontentrules */
85 
86 struct schema_private_data {
87 	struct ldb_dn *schema_dn;
88 	struct schema_attribute **attrs;
89 	struct schema_store *attrs_store;
90 	int num_attributes;
91 	struct schema_class **class;
92 	struct schema_store *class_store;
93 	int num_classes;
94 };
95 
96 struct schema_class_dlist {
97 	struct schema_class *class;
98 	struct schema_class_dlist *prev;
99 	struct schema_class_dlist *next;
100 	enum schema_class_type role;
101 };
102 
103 struct schema_context {
104 
105 	enum sc_op { SC_ADD, SC_MOD, SC_DEL, SC_RENAME } op;
106 	enum sc_step { SC_INIT, SC_ADD_CHECK_PARENT, SC_ADD_TEMP, SC_DEL_CHECK_CHILDREN } step;
107 
108 	struct schema_private_data *data;
109 
110 	struct ldb_module *module;
111 	struct ldb_request *orig_req;
112 	struct ldb_request *down_req;
113 
114 	struct ldb_request *parent_req;
115 	struct ldb_reply *parent_res;
116 
117 	struct schema_class_dlist *class_list;
118 	struct schema_class **sup_list;
119 	struct schema_class **aux_list;
120 };
121 
122 /* FIXME: I'd really like to use an hash table here */
123 struct schema_link {
124 	const char *name;
125 	void *object;
126 };
127 
128 struct schema_store {
129 	struct schema_link *store;
130 	int num_links;
131 };
132 
schema_store_new(TALLOC_CTX * mem_ctx)133 static struct schema_store *schema_store_new(TALLOC_CTX *mem_ctx)
134 {
135 	struct schema_store *ht;
136 
137 	ht = talloc(mem_ctx, struct schema_store);
138 	if (!ht) return NULL;
139 
140 	ht->store = NULL;
141 	ht->num_links = 0;
142 
143 	return ht;
144 }
145 
schema_store_add(struct schema_store * ht,const char * key,void * object)146 static int schema_store_add(struct schema_store *ht, const char *key, void *object)
147 {
148 	ht->store = talloc_realloc(ht, ht->store, struct schema_link, ht->num_links + 1);
149 	if (!ht->store) return LDB_ERR_OPERATIONS_ERROR;
150 
151 	ht->store[ht->num_links].name = key;
152 	ht->store[ht->num_links].object = object;
153 
154 	ht->num_links++;
155 
156 	return LDB_SUCCESS;
157 }
158 
schema_store_find(struct schema_store * ht,const char * key)159 static void *schema_store_find(struct schema_store *ht, const char *key)
160 {
161 	int i;
162 
163 	for (i = 0; i < ht->num_links; i++) {
164 		if (strcasecmp(ht->store[i].name, key) == 0) {
165 			return ht->store[i].object;
166 		}
167 	}
168 
169 	return NULL;
170 }
171 
172 #define SCHEMA_CHECK_VALUE(mem, val, mod) \
173 		do { if (mem == val) { \
174 			ret = LDB_ERR_OPERATIONS_ERROR; \
175 			ldb_asprintf_errstring(mod->ldb, \
176 				"schema module: Memory allocation or attribute error on %s", #mem); \
177 			goto done; } } while(0)
178 
schema_get_class_list(struct ldb_module * module,struct schema_private_data * data,struct ldb_message_element * el)179 struct schema_class **schema_get_class_list(struct ldb_module *module,
180 					    struct schema_private_data *data,
181 					    struct ldb_message_element *el)
182 {
183 	struct schema_class **list;
184 	int i;
185 
186 	list = talloc_array(data, struct schema_class *, el->num_values + 1);
187 	if (!list) {
188 		ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
189 		return NULL;
190 	}
191 
192 	for (i = 0; i < el->num_values; i++) {
193 		list[i] = (struct schema_class *)schema_store_find(data->class_store,
194 								  (char *)el->values[i].data);
195 		if (!list[i]) {
196 			ldb_debug_set(module->ldb,
197 					LDB_DEBUG_ERROR,
198 					"Class %s referenced but not found in schema\n",
199 					(char *)el->values[i].data);
200 			return NULL;
201 		}
202 	}
203 	list[i] = NULL;
204 
205 	return list;
206 }
207 
schema_get_attrs_list(struct ldb_module * module,struct schema_private_data * data,struct ldb_message_element * el)208 struct schema_attribute **schema_get_attrs_list(struct ldb_module *module,
209 						struct schema_private_data *data,
210 						struct ldb_message_element *el)
211 {
212 	struct schema_attribute **list;
213 	int i;
214 
215 	list = talloc_array(data, struct schema_attribute *, el->num_values + 1);
216 	if (!list) {
217 		ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of Memory");
218 		return NULL;
219 	}
220 
221 	for (i = 0; i < el->num_values; i++) {
222 		list[i] = (struct schema_attribute *)schema_store_find(data->attrs_store,
223 								      (char *)el->values[i].data);
224 		if (!list[i]) {
225 			ldb_debug_set(module->ldb,
226 					LDB_DEBUG_ERROR,
227 					"Attriobute %s referenced but not found in schema\n",
228 					(char *)el->values[i].data);
229 			return NULL;
230 		}
231 	}
232 	list[i] = NULL;
233 
234 	return list;
235 }
236 
schema_init_attrs(struct ldb_module * module,struct schema_private_data * data)237 static int schema_init_attrs(struct ldb_module *module, struct schema_private_data *data)
238 {
239 	static const char *schema_attrs[] = {	"attributeID",
240 						"lDAPDisplayName",
241 						"attributeSyntax",
242 						"oMSyntax",
243 						"oMObjectClass",
244 						"isSingleValued",
245 						"rangeLower",
246 						"rangeUpper",
247 						"searchFlag",
248 						"systemFlag",
249 						"isDefunct",
250 						NULL };
251 	struct ldb_result *res;
252 	int ret, i;
253 
254 	ret = ldb_search(module->ldb,
255 			 data->schema_dn,
256 			 LDB_SCOPE_SUBTREE,
257 			 "(objectClass=attributeSchema)",
258 			 schema_attrs,
259 			 &res);
260 
261 	if (ret != LDB_SUCCESS) {
262 		goto done;
263 	}
264 
265 	data->num_attributes = res->count;
266 	data->attrs = talloc_array(data, struct schema_attribute *, res->count);
267 	SCHEMA_CHECK_VALUE(data->attrs, NULL, module);
268 
269 	data->attrs_store = schema_store_new(data);
270 	SCHEMA_CHECK_VALUE(data->attrs_store, NULL, module);
271 
272 	for (i = 0; i < res->count; i++) {
273 		const char *tmp_single;
274 		const char *attr_syntax;
275 		uint32_t om_syntax;
276 		const struct ldb_val *om_class;
277 
278 		data->attrs[i] = talloc(data->attrs, struct schema_attribute);
279 		SCHEMA_CHECK_VALUE(data->attrs[i], NULL, module);
280 
281 		data->attrs[i]->OID = talloc_strdup(data->attrs[i],
282 						ldb_msg_find_attr_as_string(res->msgs[i], "attributeID", NULL));
283 		SCHEMA_CHECK_VALUE(data->attrs[i]->OID, NULL, module);
284 
285 		data->attrs[i]->name = talloc_strdup(data->attrs[i],
286 						ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
287 		SCHEMA_CHECK_VALUE(data->attrs[i]->name, NULL, module);
288 
289 		/* once we have both the OID and the attribute name, add the pointer to the store */
290 		schema_store_add(data->attrs_store, data->attrs[i]->OID, data->attrs[i]);
291 		schema_store_add(data->attrs_store, data->attrs[i]->name, data->attrs[i]);
292 
293 		attr_syntax = ldb_msg_find_attr_as_string(res->msgs[i], "attributeSyntax", NULL);
294 		SCHEMA_CHECK_VALUE(attr_syntax, NULL, module);
295 
296 		om_syntax = ldb_msg_find_attr_as_uint(res->msgs[i], "oMSyntax", 0);
297 		/* 0 is not a valid oMSyntax */
298 		SCHEMA_CHECK_VALUE(om_syntax, 0, module);
299 
300 		om_class = ldb_msg_find_ldb_val(res->msgs[i], "oMObjectClass");
301 
302 		ret = map_schema_syntax(om_syntax, attr_syntax, om_class, &data->attrs[i]->syntax);
303 		if (ret != LDB_SUCCESS) {
304 			ldb_asprintf_errstring(module->ldb,
305 				"schema module: invalid om syntax value on %s",
306 				data->attrs[i]->name);
307 			goto done;
308 		}
309 
310 		tmp_single = ldb_msg_find_attr_as_string(res->msgs[i], "isSingleValued", NULL);
311 		SCHEMA_CHECK_VALUE(tmp_single, NULL, module);
312 		if (strcmp(tmp_single, "TRUE") == 0) {
313 			data->attrs[i]->single = 1;
314 		} else {
315 			data->attrs[i]->single = 0;
316 		}
317 
318 		/* the following are optional */
319 		data->attrs[i]->min = ldb_msg_find_attr_as_int(res->msgs[i], "rangeLower", INT_MIN);
320 		data->attrs[i]->max = ldb_msg_find_attr_as_int(res->msgs[i], "rangeUpper", INT_MAX);
321 		data->attrs[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
322 		data->attrs[i]->searchflag = ldb_msg_find_attr_as_int(res->msgs[i], "searchFlag", 0);
323 		data->attrs[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", False);
324 	}
325 
326 done:
327 	talloc_free(res);
328 	return ret;
329 }
330 
schema_init_classes(struct ldb_module * module,struct schema_private_data * data)331 static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data)
332 {
333 	static const char *schema_attrs[] = {	"governsID",
334 						"lDAPDisplayName",
335 						"objectClassCategory",
336 						"defaultObjectCategory",
337 						"systemOnly",
338 						"systemFlag",
339 						"isDefunct",
340 						"subClassOf",
341 						"systemAuxiliaryClass",
342 						"auxiliaryClass",
343 						"systemPossSuperiors",
344 						"possSuperiors",
345 						"possibleInferiors",
346 						"systemMustContain",
347 						"MustContain",
348 						"systemMayContain",
349 						"MayContain",
350 						NULL };
351 	struct ldb_result *res;
352 	int ret, i;
353 
354 	ret = ldb_search(module->ldb,
355 			 data->schema_dn,
356 			 LDB_SCOPE_SUBTREE,
357 			 "(objectClass=classSchema)",
358 			 schema_attrs,
359 			 &res);
360 
361 	if (ret != LDB_SUCCESS) {
362 		goto done;
363 	}
364 
365 	data->num_classes = res->count;
366 	data->class = talloc_array(data, struct schema_class *, res->count);
367 	SCHEMA_CHECK_VALUE(data->class, NULL, module);
368 
369 	data->class_store = schema_store_new(data);
370 	SCHEMA_CHECK_VALUE(data->class_store, NULL, module);
371 
372 	for (i = 0; i < res->count; i++) {
373 		struct ldb_message_element *el;
374 
375 		data->class[i] = talloc(data->class, struct schema_class);
376 		SCHEMA_CHECK_VALUE(data->class[i], NULL, module);
377 
378 		data->class[i]->OID = talloc_strdup(data->class[i],
379 						ldb_msg_find_attr_as_string(res->msgs[i], "governsID", NULL));
380 		SCHEMA_CHECK_VALUE(data->class[i]->OID, NULL, module);
381 
382 		data->class[i]->name = talloc_strdup(data->class[i],
383 						ldb_msg_find_attr_as_string(res->msgs[i], "lDAPDisplayName", NULL));
384 		SCHEMA_CHECK_VALUE(data->class[i]->name, NULL, module);
385 
386 		/* once we have both the OID and the class name, add the pointer to the store */
387 		schema_store_add(data->class_store, data->class[i]->OID, data->class[i]);
388 		schema_store_add(data->class_store, data->class[i]->name, data->class[i]);
389 
390 		data->class[i]->type = ldb_msg_find_attr_as_int(res->msgs[i], "objectClassCategory", -1);
391 		/* 0 should not be a valid value, but turn out it is so test with -1 */
392 		SCHEMA_CHECK_VALUE(data->class[i]->type, -1, module);
393 
394 		data->class[i]->defobjcat = talloc_strdup(data->class[i],
395 						ldb_msg_find_attr_as_string(res->msgs[i],
396 									"defaultObjectCategory", NULL));
397 /*		SCHEMA_CHECK_VALUE(data->class[i]->defobjcat, NULL, module);
398 */
399 		/* the following attributes are all optional */
400 
401 		data->class[i]->systemOnly = ldb_msg_find_attr_as_bool(res->msgs[i], "systemOnly", False);
402 		data->class[i]->systemflag = ldb_msg_find_attr_as_int(res->msgs[i], "systemFlag", 0);
403 		data->class[i]->isdefunct = ldb_msg_find_attr_as_bool(res->msgs[i], "isDefunct", False);
404 
405 		/* attributes are loaded first, so we can just go an query the attributes repo */
406 
407 		el = ldb_msg_find_element(res->msgs[i], "systemMustContain");
408 		if (el) {
409 			data->class[i]->sysmust = schema_get_attrs_list(module, data, el);
410 			SCHEMA_CHECK_VALUE(data->class[i]->sysmust, NULL, module);
411 		}
412 
413 		el = ldb_msg_find_element(res->msgs[i], "MustContain");
414 		if (el) {
415 			data->class[i]->must = schema_get_attrs_list(module, data, el);
416 			SCHEMA_CHECK_VALUE(data->class[i]->must, NULL, module);
417 		}
418 
419 		el = ldb_msg_find_element(res->msgs[i], "systemMayContain");
420 		if (el) {
421 			data->class[i]->sysmay = schema_get_attrs_list(module, data, el);
422 			SCHEMA_CHECK_VALUE(data->class[i]->sysmay, NULL, module);
423 		}
424 
425 		el = ldb_msg_find_element(res->msgs[i], "MayContain");
426 		if (el) {
427 			data->class[i]->may = schema_get_attrs_list(module, data, el);
428 			SCHEMA_CHECK_VALUE(data->class[i]->may, NULL, module);
429 		}
430 
431 	}
432 
433 	/* subClassOf, systemAuxiliaryClass, auxiliaryClass, systemPossSuperiors
434 	 * must be filled in a second loop, when all class objects are allocated
435 	 * or we may not find a class that has not yet been parsed */
436 	for (i = 0; i < res->count; i++) {
437 		struct ldb_message_element *el;
438 		const char *attr;
439 
440 		/* this is single valued anyway */
441 		attr = ldb_msg_find_attr_as_string(res->msgs[i], "subClassOf", NULL);
442 		SCHEMA_CHECK_VALUE(attr, NULL, module);
443 		data->class[i]->parent = schema_store_find(data->class_store, attr);
444 		SCHEMA_CHECK_VALUE(data->class[i]->parent, NULL, module);
445 
446 		/* the following attributes are all optional */
447 
448 		data->class[i]->sysaux = NULL;
449 		el = ldb_msg_find_element(res->msgs[i], "systemAuxiliaryClass");
450 		if (el) {
451 			data->class[i]->sysaux = schema_get_class_list(module, data, el);
452 			SCHEMA_CHECK_VALUE(data->class[i]->sysaux, NULL, module);
453 		}
454 
455 		data->class[i]->aux = NULL;
456 		el = ldb_msg_find_element(res->msgs[i], "auxiliaryClass");
457 		if (el) {
458 			data->class[i]->aux = schema_get_class_list(module, data, el);
459 			SCHEMA_CHECK_VALUE(data->class[i]->aux, NULL, module);
460 		}
461 
462 		data->class[i]->sysposssup = NULL;
463 		el = ldb_msg_find_element(res->msgs[i], "systemPossSuperiors");
464 		if (el) {
465 			data->class[i]->sysposssup = schema_get_class_list(module, data, el);
466 			SCHEMA_CHECK_VALUE(data->class[i]->sysposssup, NULL, module);
467 		}
468 
469 		data->class[i]->posssup = NULL;
470 		el = ldb_msg_find_element(res->msgs[i], "possSuperiors");
471 		if (el) {
472 			data->class[i]->posssup = schema_get_class_list(module, data, el);
473 			SCHEMA_CHECK_VALUE(data->class[i]->posssup, NULL, module);
474 		}
475 
476 		data->class[i]->possinf = NULL;
477 		el = ldb_msg_find_element(res->msgs[i], "possibleInferiors");
478 		if (el) {
479 			data->class[i]->possinf = schema_get_class_list(module, data, el);
480 			SCHEMA_CHECK_VALUE(data->class[i]->possinf, NULL, module);
481 		}
482 	}
483 
484 done:
485 	talloc_free(res);
486 	return ret;
487 }
488 
schema_init_handle(struct ldb_request * req,struct ldb_module * module,enum sc_op op)489 static struct ldb_handle *schema_init_handle(struct ldb_request *req, struct ldb_module *module, enum sc_op op)
490 {
491 	struct schema_context *sctx;
492 	struct ldb_handle *h;
493 
494 	h = talloc_zero(req, struct ldb_handle);
495 	if (h == NULL) {
496 		ldb_set_errstring(module->ldb, "Out of Memory");
497 		return NULL;
498 	}
499 
500 	h->module = module;
501 
502 	sctx = talloc_zero(h, struct schema_context);
503 	if (sctx == NULL) {
504 		ldb_set_errstring(module->ldb, "Out of Memory");
505 		talloc_free(h);
506 		return NULL;
507 	}
508 
509 	h->private_data = (void *)sctx;
510 
511 	h->state = LDB_ASYNC_INIT;
512 	h->status = LDB_SUCCESS;
513 
514 	sctx->op = op;
515 	sctx->step = SC_INIT;
516 	sctx->data = module->private_data;
517 	sctx->module = module;
518 	sctx->orig_req = req;
519 
520 	return h;
521 }
522 
schema_add_check_parent(struct ldb_context * ldb,void * context,struct ldb_reply * ares)523 static int schema_add_check_parent(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
524 {
525 	struct schema_context *sctx;
526 
527 	if (!context || !ares) {
528 		ldb_set_errstring(ldb, "NULL Context or Result in callback");
529 		return LDB_ERR_OPERATIONS_ERROR;
530 	}
531 
532 	sctx = talloc_get_type(context, struct schema_context);
533 
534 	/* we are interested only in the single reply (base search) we receive here */
535 	if (ares->type == LDB_REPLY_ENTRY) {
536 		if (sctx->parent_res != NULL) {
537 			ldb_set_errstring(ldb, "Too many results");
538 			talloc_free(ares);
539 			return LDB_ERR_OPERATIONS_ERROR;
540 		}
541 		sctx->parent_res = talloc_steal(sctx, ares);
542 	} else {
543 		talloc_free(ares);
544 	}
545 
546 	return LDB_SUCCESS;
547 }
548 
schema_add_build_parent_req(struct schema_context * sctx)549 static int schema_add_build_parent_req(struct schema_context *sctx)
550 {
551 	static const char * const parent_attrs[] = { "objectClass", NULL };
552 	int ret;
553 
554 	sctx->parent_req = talloc_zero(sctx, struct ldb_request);
555 	if (sctx->parent_req == NULL) {
556 		ldb_debug(sctx->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
557 		return LDB_ERR_OPERATIONS_ERROR;
558 	}
559 
560 	sctx->parent_req->operation = LDB_SEARCH;
561 	sctx->parent_req->op.search.scope = LDB_SCOPE_BASE;
562 	sctx->parent_req->op.search.base = ldb_dn_get_parent(sctx->parent_req, sctx->orig_req->op.add.message->dn);
563 	sctx->parent_req->op.search.tree = ldb_parse_tree(sctx->parent_req, "(objectClass=*)");
564 	sctx->parent_req->op.search.attrs = parent_attrs;
565 	sctx->parent_req->controls = NULL;
566 	sctx->parent_req->context = sctx;
567 	sctx->parent_req->callback = schema_add_check_parent;
568 	ret = ldb_set_timeout_from_prev_req(sctx->module->ldb, sctx->orig_req, sctx->parent_req);
569 
570 	return ret;
571 }
572 
schema_add_get_dlist_entry_with_class(struct schema_class_dlist * list,struct schema_class * class)573 static struct schema_class_dlist *schema_add_get_dlist_entry_with_class(struct schema_class_dlist *list, struct schema_class *class)
574 {
575 	struct schema_class_dlist *temp;
576 
577 	for (temp = list; temp && (temp->class != class); temp = temp->next) /* noop */ ;
578 	return temp;
579 }
580 
schema_add_class_to_dlist(struct schema_class_dlist * list,struct schema_class * class,enum schema_class_type role)581 static int schema_add_class_to_dlist(struct schema_class_dlist *list, struct schema_class *class, enum schema_class_type role)
582 {
583 	struct schema_class_dlist *entry;
584 	struct schema_class_dlist *temp;
585 	int ret;
586 
587 	/* see if this class is usable */
588 	if (class->isdefunct) {
589 		return LDB_ERR_NO_SUCH_ATTRIBUTE;
590 	}
591 
592 	/* see if this class already exist in the class list */
593 	if (schema_add_get_dlist_entry_with_class(list, class)) {
594 		return LDB_SUCCESS;
595 	}
596 
597 	/* this is a new class go on and add to the list */
598 	entry = talloc_zero(list, struct schema_class_dlist);
599 	if (!entry) return LDB_ERR_OPERATIONS_ERROR;
600 	entry->class = class;
601 	entry->role = class->type;
602 
603 	/* If parent is top (list is guaranteed to start always with top) */
604 	if (class->parent == list->class) {
605 		/* if the hierarchy role is structural try to add it just after top */
606 		if (role == SCHEMA_CT_STRUCTURAL) {
607 			/* but check no other class at after top has a structural role */
608 			if (list->next && (list->next->role == SCHEMA_CT_STRUCTURAL)) {
609 				return LDB_ERR_OBJECT_CLASS_VIOLATION;
610 			}
611 			DLIST_ADD_AFTER(list, entry, list);
612 		} else {
613 			DLIST_ADD_END(list, entry, struct schema_class_dlist *);
614 		}
615 		return LDB_SUCCESS;
616 	}
617 
618 	/* search if parent has already been added */
619 	temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
620 	if (temp == NULL) {
621 		ret = schema_add_class_to_dlist(list, class->parent, role);
622 		if (ret != LDB_SUCCESS) {
623 			return ret;
624 		}
625 		temp = schema_add_get_dlist_entry_with_class(list->next, class->parent);
626 	}
627 	if (!temp) { /* parent not found !? */
628 		return LDB_ERR_OPERATIONS_ERROR;
629 	}
630 
631 	DLIST_ADD_AFTER(list, entry, temp);
632 	if (role == SCHEMA_CT_STRUCTURAL || role == SCHEMA_CT_AUXILIARY) {
633 		temp = entry;
634 		do {
635 			temp->role = role;
636 			temp = temp->prev;
637 			/* stop when hierarchy base is met or when base class parent is top */
638 		} while (temp->class == temp->next->class->parent &&
639 			 temp->next->class->parent != list->class);
640 
641 		/* if we have not reached the head of the list
642 		 * and role is structural */
643 		if (temp != list && role == SCHEMA_CT_STRUCTURAL) {
644 			struct schema_class_dlist *hfirst, *hlast;
645 
646 			/* check if the list second entry is structural */
647 			if (list->next->role == SCHEMA_CT_STRUCTURAL) {
648 				/* we have a confilict here */
649 				return LDB_ERR_OBJECT_CLASS_VIOLATION;
650 			}
651 			/* we have to move this hierarchy of classes
652 			 * so that the base of the structural hierarchy is right after top */
653 
654 			hfirst = temp->next;
655 			hlast = entry;
656 			/* now hfirst - hlast are the boundaries of the structural hierarchy */
657 
658 			/* extract the structural hierachy from the list */
659 			hfirst->prev->next = hlast->next;
660 			if (hlast->next) hlast->next->prev = hfirst->prev;
661 
662 			/* insert the structural hierarchy just after top */
663 			list->next->prev = hlast;
664 			hlast->next = list->next;
665 			list->next = hfirst;
666 			hfirst->prev = list;
667 		}
668 	}
669 
670 	return LDB_SUCCESS;
671 }
672 
673 /* merge source list into dest list and remove duplicates */
schema_merge_class_list(TALLOC_CTX * mem_ctx,struct schema_class *** dest,struct schema_class ** source)674 static int schema_merge_class_list(TALLOC_CTX *mem_ctx, struct schema_class ***dest, struct schema_class **source)
675 {
676 	struct schema_class **list = *dest;
677 	int i, j, n, f;
678 
679 	n = 0;
680 	if (list) for (n = 0; list[n]; n++) /* noop */ ;
681 	f = n;
682 
683 	for (i = 0; source[i]; i++) {
684 		for (j = 0; j < f; j++) {
685 			if (list[j] == source[i]) {
686 				break;
687 			}
688 		}
689 		if (j < f) { /* duplicate found */
690 			continue;
691 		}
692 
693 		list = talloc_realloc(mem_ctx, list, struct schema_class *, n + 2);
694 		if (!list) {
695 			return LDB_ERR_OPERATIONS_ERROR;
696 		}
697 		list[n] = source[i];
698 		n++;
699 		list[n] = NULL;
700 	}
701 
702 	*dest = list;
703 
704 	return LDB_SUCCESS;
705 }
706 
707 /* validate and modify the objectclass attribute to sort and add parents */
schema_add_build_objectclass_list(struct schema_context * sctx)708 static int schema_add_build_objectclass_list(struct schema_context *sctx)
709 {
710 	struct schema_class_dlist *temp;
711 	struct ldb_message_element * el;
712 	struct schema_class *class;
713 	int ret, i, an;
714 
715 	/* First of all initialize list, it must start with class top */
716 	sctx->class_list = talloc_zero(sctx, struct schema_class_dlist);
717 	if (!sctx->class_list) return LDB_ERR_OPERATIONS_ERROR;
718 
719 	sctx->class_list->class = schema_store_find(sctx->data->class_store, "top");
720 	if (!sctx->class_list->class) return LDB_ERR_OPERATIONS_ERROR;
721 
722 	el = ldb_msg_find_element(sctx->orig_req->op.add.message, "objectClass");
723 	if (!el) {
724 		return LDB_ERR_OBJECT_CLASS_VIOLATION;
725 	}
726 
727 	for (i = 0; i < el->num_values; i++) {
728 
729 		class = schema_store_find(sctx->data->class_store, (char *)el->values[i].data);
730 		if (!class) {
731 			return LDB_ERR_NO_SUCH_ATTRIBUTE;
732 		}
733 
734 		ret = schema_add_class_to_dlist(sctx->class_list, class, class->type);
735 		if (ret != LDB_SUCCESS) {
736 			return ret;
737 		}
738 	}
739 
740 	/* now check if there is any class role that is still not STRUCTURAL or AUXILIARY */
741 	/* build also the auxiliary class list and the possible superiors list */
742 	temp = sctx->class_list->next; /* top is special, skip it */
743 	an = 0;
744 
745 	while (temp) {
746 		if (temp->role == SCHEMA_CT_ABSTRACT || temp->role == SCHEMA_CT_88) {
747 			return LDB_ERR_OBJECT_CLASS_VIOLATION;
748 		}
749 		if (temp->class->sysaux) {
750 			ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->sysaux);
751 			if (ret != LDB_SUCCESS) {
752 				return LDB_ERR_OPERATIONS_ERROR;
753 			}
754 		}
755 		if (temp->class->aux) {
756 			ret = schema_merge_class_list(sctx, &sctx->aux_list, temp->class->aux);
757 			if (ret != LDB_SUCCESS) {
758 				return LDB_ERR_OPERATIONS_ERROR;
759 			}
760 		}
761 		if (temp->class->sysposssup) {
762 			ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->sysposssup);
763 			if (ret != LDB_SUCCESS) {
764 				return LDB_ERR_OPERATIONS_ERROR;
765 			}
766 		}
767 		if (temp->class->posssup) {
768 			ret = schema_merge_class_list(sctx, &sctx->sup_list, temp->class->posssup);
769 			if (ret != LDB_SUCCESS) {
770 				return LDB_ERR_OPERATIONS_ERROR;
771 			}
772 		}
773 		temp = temp->next;
774 	}
775 
776 	/* complete sup_list with material from the aux classes */
777 	for (i = 0; sctx->aux_list && sctx->aux_list[i]; i++) {
778 		if (sctx->aux_list[i]->sysposssup) {
779 			ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->sysposssup);
780 			if (ret != LDB_SUCCESS) {
781 				return LDB_ERR_OPERATIONS_ERROR;
782 			}
783 		}
784 		if (sctx->aux_list[i]->posssup) {
785 			ret = schema_merge_class_list(sctx, &sctx->sup_list, sctx->aux_list[i]->posssup);
786 			if (ret != LDB_SUCCESS) {
787 				return LDB_ERR_OPERATIONS_ERROR;
788 			}
789 		}
790 	}
791 
792 	if (!sctx->sup_list) return LDB_ERR_NAMING_VIOLATION;
793 
794 	return LDB_SUCCESS;
795 }
796 
schema_add_check_container_constraints(struct schema_context * sctx)797 static int schema_add_check_container_constraints(struct schema_context *sctx)
798 {
799 	struct schema_class **parent_possinf = NULL;
800 	struct schema_class **parent_classes;
801 	struct schema_class_dlist *temp;
802 	struct ldb_message_element *el;
803 	int i, j, ret;
804 
805 	el = ldb_msg_find_element(sctx->parent_res->message, "objectClass");
806 	if (!el) {
807 		/* what the .. */
808 		return LDB_ERR_OPERATIONS_ERROR;
809 	}
810 
811 	parent_classes = talloc_array(sctx, struct schema_class *, el->num_values + 1);
812 
813 	for (i = 0; i < el->num_values; i++) {
814 
815 		parent_classes[i] = schema_store_find(sctx->data->class_store, (const char *)el->values[i].data);
816 		if (!parent_classes[i]) { /* should not be possible */
817 			return LDB_ERR_OPERATIONS_ERROR;
818 		}
819 
820 		if (parent_classes[i]->possinf) {
821 			ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->possinf);
822 			if (ret != LDB_SUCCESS) {
823 				return LDB_ERR_OPERATIONS_ERROR;
824 			}
825 		}
826 
827 		/* check also embedded auxiliary classes possinf */
828 		for (j = 0; parent_classes[i]->sysaux && parent_classes[i]->sysaux[j]; j++) {
829 			if (parent_classes[i]->sysaux[j]->possinf) {
830 				ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->sysaux[j]->possinf);
831 				if (ret != LDB_SUCCESS) {
832 					return LDB_ERR_OPERATIONS_ERROR;
833 				}
834 			}
835 		}
836 		for (j = 0; parent_classes[i]->aux && parent_classes[i]->aux[j]; j++) {
837 			if (parent_classes[i]->aux[j]->possinf) {
838 				ret = schema_merge_class_list(sctx, &parent_possinf, parent_classes[i]->aux[j]->possinf);
839 				if (ret != LDB_SUCCESS) {
840 					return LDB_ERR_OPERATIONS_ERROR;
841 				}
842 			}
843 		}
844 	}
845 
846 	/* foreach parent objectclass,
847 	 *   check parent possible inferiors match all of the child objectclasses
848 	 *    and that
849 	 *   poss Superiors of the child objectclasses mathes one of the parent classes
850 	 */
851 
852 	temp = sctx->class_list->next; /* skip top it is special */
853 	while (temp) {
854 
855 		for (i = 0; parent_possinf[i]; i++) {
856 			if (temp->class == parent_possinf[i]) {
857 				break;
858 			}
859 		}
860 		if (parent_possinf[i] == NULL) {
861 			/* class not found in possible inferiors */
862 			return LDB_ERR_NAMING_VIOLATION;
863 		}
864 
865 		temp = temp->next;
866 	}
867 
868 	for (i = 0; parent_classes[i]; i++) {
869 		for (j = 0; sctx->sup_list[j]; j++) {
870 			if (sctx->sup_list[j] == parent_classes[i]) {
871 				break;
872 			}
873 		}
874 		if (sctx->sup_list[j]) { /* possible Superiors match one of the parent classes */
875 			return LDB_SUCCESS;
876 		}
877 	}
878 
879 	/* no parent classes matched superiors */
880 	return LDB_ERR_NAMING_VIOLATION;
881 }
882 
schema_add_build_down_req(struct schema_context * sctx)883 static int schema_add_build_down_req(struct schema_context *sctx)
884 {
885 	struct schema_class_dlist *temp;
886 	struct ldb_message *msg;
887 	char *oc;
888 	int ret;
889 
890 	sctx->down_req = talloc(sctx, struct ldb_request);
891 	if (!sctx->down_req) {
892 		ldb_set_errstring(sctx->module->ldb, "Out of memory!");
893 		return LDB_ERR_OPERATIONS_ERROR;
894 	}
895 
896 	*(sctx->down_req) = *(sctx->orig_req); /* copy the request */
897 	msg = ldb_msg_copy_shallow(sctx->down_req, sctx->orig_req->op.add.message);
898 	if (!msg) {
899 		ldb_set_errstring(sctx->module->ldb, "Out of memory!");
900 		return LDB_ERR_OPERATIONS_ERROR;
901 	}
902 
903 	/* rebuild the objectclass list */
904 	ldb_msg_remove_attr(msg, "objectClass");
905 	ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
906 	if (ret != LDB_SUCCESS) {
907 		return ret;
908 	}
909 
910 	/* Add the complete list of classes back to the message */
911 	for (temp = sctx->class_list; temp; temp = temp->next) {
912 		ret = ldb_msg_add_string(msg, "objectClass", temp->class->name);
913 		if (ret != LDB_SUCCESS) {
914 			return ret;
915 		}
916 	}
917 
918 	/* objectCategory can be set only by the system */
919 	if (ldb_msg_find_element(msg, "objectCategory")) {
920 		return LDB_ERR_CONSTRAINT_VIOLATION;
921 	}
922 
923 	/* the OC is mandatory, every class defines it */
924 	/* use the one defined in the structural class that defines the object */
925 	for (temp = sctx->class_list->next; temp; temp = temp->next) {
926 		if (!temp->next) break;
927 		if (temp->next->role != SCHEMA_CT_STRUCTURAL) break;
928 	}
929 /*	oc = talloc_strdup(msg, temp->class->defobjcat);
930 	ret = ldb_msg_add_string(msg, "objectCategory", oc);
931 */
932 	sctx->down_req->op.add.message = msg;
933 
934 	return LDB_SUCCESS;
935 }
936 
schema_check_attributes_syntax(struct schema_context * sctx)937 static int schema_check_attributes_syntax(struct schema_context *sctx)
938 {
939 	struct ldb_message *msg;
940 	struct schema_attribute *attr;
941 	int i, ret;
942 
943 	msg = sctx->orig_req->op.add.message;
944 	for (i = 0; i < msg->num_elements; i++) {
945 		attr = schema_store_find(sctx->data->attrs_store, msg->elements[i].name);
946 		if (attr == NULL) {
947 			return LDB_ERR_NO_SUCH_ATTRIBUTE;
948 		}
949 		ret = schema_validate(sctx->module->ldb, &msg->elements[i], attr->syntax, attr->single, attr->min, attr->max);
950 		if (ret != LDB_SUCCESS) {
951 			return ret;
952 		}
953 	}
954 
955 	return LDB_SUCCESS;
956 }
957 
schema_add_continue(struct ldb_handle * h)958 static int schema_add_continue(struct ldb_handle *h)
959 {
960 	struct schema_context *sctx;
961 	int ret;
962 
963 	sctx = talloc_get_type(h->private_data, struct schema_context);
964 
965 	switch (sctx->step) {
966 	case SC_INIT:
967 
968 		/* First of all check that a parent exists for this entry */
969 		ret = schema_add_build_parent_req(sctx);
970 		if (ret != LDB_SUCCESS) {
971 			break;
972 		}
973 
974 		sctx->step = SC_ADD_CHECK_PARENT;
975 		return ldb_next_request(sctx->module, sctx->parent_req);
976 
977 	case SC_ADD_CHECK_PARENT:
978 
979 		/* parent search done, check result and go on */
980 		if (sctx->parent_res == NULL) {
981 			/* we must have a parent */
982 			ret = LDB_ERR_NO_SUCH_OBJECT;
983 			break;
984 		}
985 
986 		/* Check objectclasses are ok */
987 		ret = schema_add_build_objectclass_list(sctx);
988 	       	if (ret != LDB_SUCCESS) {
989 			break;
990 		}
991 
992 		/* check the parent is of the right type for this object */
993 		ret = schema_add_check_container_constraints(sctx);
994 	       	if (ret != LDB_SUCCESS) {
995 			break;
996 		}
997 
998 		/* check attributes syntax */
999 
1000 		ret = schema_check_attributes_syntax(sctx);
1001 		if (ret != LDB_SUCCESS) {
1002 			break;
1003 		}
1004 
1005 		ret = schema_add_build_down_req(sctx);
1006 		if (ret != LDB_SUCCESS) {
1007 			break;
1008 		}
1009 		sctx->step = SC_ADD_TEMP;
1010 
1011 		return ldb_next_request(sctx->module, sctx->down_req);
1012 
1013 	default:
1014 		ret = LDB_ERR_OPERATIONS_ERROR;
1015 		break;
1016 	}
1017 
1018 	/* this is reached only in case of error */
1019 	/* FIXME: fire an async reply ? */
1020 	h->status = ret;
1021 	h->state = LDB_ASYNC_DONE;
1022 	return ret;
1023 }
1024 
schema_add(struct ldb_module * module,struct ldb_request * req)1025 static int schema_add(struct ldb_module *module, struct ldb_request *req)
1026 {
1027 	struct schema_context *sctx;
1028 	struct ldb_handle *h;
1029 
1030 	if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
1031 		return ldb_next_request(module, req);
1032 	}
1033 
1034 	h = schema_init_handle(req, module, SC_ADD);
1035 	if (!h) {
1036 		return LDB_ERR_OPERATIONS_ERROR;
1037 	}
1038 
1039 	sctx = talloc_get_type(h->private_data, struct schema_context);
1040 	sctx->orig_req->handle = h;
1041 	return schema_add_continue(h);
1042 }
1043 
1044 
schema_modify(struct ldb_module * module,struct ldb_request * req)1045 static int schema_modify(struct ldb_module *module, struct ldb_request *req)
1046 {
1047 	if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1048 		return ldb_next_request(module, req);
1049 	}
1050 
1051 	return ldb_next_request(module, req);
1052 }
1053 
schema_delete(struct ldb_module * module,struct ldb_request * req)1054 static int schema_delete(struct ldb_module *module, struct ldb_request *req)
1055 {
1056 	if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */
1057 		return ldb_next_request(module, req);
1058 	}
1059 
1060 	/* First of all check no children exists for this entry */
1061 
1062 	return ldb_next_request(module, req);
1063 }
1064 
schema_rename(struct ldb_module * module,struct ldb_request * req)1065 static int schema_rename(struct ldb_module *module, struct ldb_request *req)
1066 {
1067 	if (ldb_dn_is_special(req->op.rename.olddn) &&
1068 	    ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
1069 		return ldb_next_request(module, req);
1070 	}
1071 
1072 	return ldb_next_request(module, req);
1073 }
1074 
schema_wait_loop(struct ldb_handle * handle)1075 static int schema_wait_loop(struct ldb_handle *handle) {
1076 	struct schema_context *sctx;
1077 	int ret;
1078 
1079 	if (!handle || !handle->private_data) {
1080 		return LDB_ERR_OPERATIONS_ERROR;
1081 	}
1082 
1083 	if (handle->state == LDB_ASYNC_DONE) {
1084 		return handle->status;
1085 	}
1086 
1087 	handle->state = LDB_ASYNC_PENDING;
1088 	handle->status = LDB_SUCCESS;
1089 
1090 	sctx = talloc_get_type(handle->private_data, struct schema_context);
1091 
1092 	switch (sctx->step) {
1093 	case SC_ADD_CHECK_PARENT:
1094 		ret = ldb_wait(sctx->parent_req->handle, LDB_WAIT_NONE);
1095 
1096 		if (ret != LDB_SUCCESS) {
1097 			handle->status = ret;
1098 			goto done;
1099 		}
1100 		if (sctx->parent_req->handle->status != LDB_SUCCESS) {
1101 			handle->status = sctx->parent_req->handle->status;
1102 			goto done;
1103 		}
1104 
1105 		if (sctx->parent_req->handle->state != LDB_ASYNC_DONE) {
1106 			return LDB_SUCCESS;
1107 		}
1108 
1109 		return schema_add_continue(handle);
1110 
1111 	case SC_ADD_TEMP:
1112 		ret = ldb_wait(sctx->down_req->handle, LDB_WAIT_NONE);
1113 
1114 		if (ret != LDB_SUCCESS) {
1115 			handle->status = ret;
1116 			goto done;
1117 		}
1118 		if (sctx->down_req->handle->status != LDB_SUCCESS) {
1119 			handle->status = sctx->down_req->handle->status;
1120 			goto done;
1121 		}
1122 
1123 		if (sctx->down_req->handle->state != LDB_ASYNC_DONE) {
1124 			return LDB_SUCCESS;
1125 		}
1126 
1127 		break;
1128 
1129 	default:
1130 		ret = LDB_ERR_OPERATIONS_ERROR;
1131 		goto done;
1132 	}
1133 
1134 	ret = LDB_SUCCESS;
1135 
1136 done:
1137 	handle->state = LDB_ASYNC_DONE;
1138 	return ret;
1139 }
1140 
schema_wait_all(struct ldb_handle * handle)1141 static int schema_wait_all(struct ldb_handle *handle) {
1142 
1143 	int ret;
1144 
1145 	while (handle->state != LDB_ASYNC_DONE) {
1146 		ret = schema_wait_loop(handle);
1147 		if (ret != LDB_SUCCESS) {
1148 			return ret;
1149 		}
1150 	}
1151 
1152 	return handle->status;
1153 }
1154 
schema_wait(struct ldb_handle * handle,enum ldb_wait_type type)1155 static int schema_wait(struct ldb_handle *handle, enum ldb_wait_type type)
1156 {
1157 	if (type == LDB_WAIT_ALL) {
1158 		return schema_wait_all(handle);
1159 	} else {
1160 		return schema_wait_loop(handle);
1161 	}
1162 }
1163 
schema_init(struct ldb_module * module)1164 static int schema_init(struct ldb_module *module)
1165 {
1166 	static const char *schema_attrs[] = { "schemaNamingContext", NULL };
1167 	struct schema_private_data *data;
1168 	struct ldb_result *res;
1169 	int ret;
1170 
1171 	/* need to let the partition module to register first */
1172 	ret = ldb_next_init(module);
1173 	if (ret != LDB_SUCCESS) {
1174 		return ret;
1175 	}
1176 
1177 	data = ldb_get_opaque(module->ldb, "schema_instance");
1178 	if (data) {
1179 		module->private_data = data;
1180 		return LDB_SUCCESS;
1181 	}
1182 
1183 	data = talloc_zero(module->ldb, struct schema_private_data);
1184 	if (data == NULL) {
1185 		return LDB_ERR_OPERATIONS_ERROR;
1186 	}
1187 
1188 	/* find the schema partition */
1189 	ret = ldb_search(module->ldb,
1190 			 ldb_dn_new(module, module->ldb, NULL),
1191 			 LDB_SCOPE_BASE,
1192 			 "(objectClass=*)",
1193 			 schema_attrs,
1194 			 &res);
1195 
1196 	if (res->count != 1) {
1197 		/* FIXME: return a clear error string */
1198 		talloc_free(data);
1199 		talloc_free(res);
1200 		return LDB_ERR_OPERATIONS_ERROR;
1201 	}
1202 
1203 	data->schema_dn = ldb_msg_find_attr_as_dn(module->ldb, data, res->msgs[0], "schemaNamingContext");
1204 	if (data->schema_dn == NULL) {
1205 		/* FIXME: return a clear error string */
1206 		talloc_free(data);
1207 		talloc_free(res);
1208 		return LDB_ERR_OPERATIONS_ERROR;
1209 	}
1210 
1211 	talloc_free(res);
1212 
1213 	ret = schema_init_attrs(module, data);
1214 	if (ret != LDB_SUCCESS) {
1215 		talloc_free(data);
1216 		return ret;
1217 	}
1218 
1219 	ret = schema_init_classes(module, data);
1220 	if (ret != LDB_SUCCESS) {
1221 		talloc_free(data);
1222 		return ret;
1223 	}
1224 
1225 	module->private_data = data;
1226 	ldb_set_opaque(module->ldb, "schema_instance", data);
1227 
1228 	return LDB_SUCCESS;
1229 }
1230 
1231 static const struct ldb_module_ops schema_ops = {
1232 	.name          = "schema",
1233 	.init_context  = schema_init,
1234 	.add           = schema_add,
1235 	.modify        = schema_modify,
1236 	.del           = schema_delete,
1237 	.rename        = schema_rename,
1238 	.wait          = schema_wait
1239 };
1240 
ldb_schema_init(void)1241 int ldb_schema_init(void)
1242 {
1243 	return ldb_register_module(&schema_ops);
1244 }
1245