Line data Source code
1 : /*
2 : Samba4 module loading module
3 :
4 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
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 3 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, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : /*
21 : * Name: ldb
22 : *
23 : * Component: Samba4 module loading module
24 : *
25 : * Description: Implement a single 'module' in the ldb database,
26 : * which loads the remaining modules based on 'choice of configuration' attributes
27 : *
28 : * This is to avoid forcing a reprovision of the ldb databases when we change the internal structure of the code
29 : *
30 : * Author: Andrew Bartlett
31 : */
32 :
33 : #include "includes.h"
34 : #include <ldb.h>
35 : #include <ldb_errors.h>
36 : #include <ldb_module.h>
37 : #include "dsdb/samdb/ldb_modules/util.h"
38 : #include "dsdb/samdb/samdb.h"
39 : #include "librpc/ndr/libndr.h"
40 : #include "auth/credentials/credentials.h"
41 : #include "param/secrets.h"
42 : #include "lib/ldb-samba/ldb_wrap.h"
43 :
44 182010 : static int read_at_rootdse_record(struct ldb_context *ldb, struct ldb_module *module, TALLOC_CTX *mem_ctx,
45 : struct ldb_message **msg, struct ldb_request *parent)
46 : {
47 6016 : int ret;
48 6016 : static const char *rootdse_attrs[] = { "defaultNamingContext", "configurationNamingContext", "schemaNamingContext", NULL };
49 6016 : struct ldb_result *rootdse_res;
50 6016 : struct ldb_dn *rootdse_dn;
51 182010 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
52 182010 : if (!tmp_ctx) {
53 0 : return ldb_oom(ldb);
54 : }
55 :
56 182010 : rootdse_dn = ldb_dn_new(tmp_ctx, ldb, "@ROOTDSE");
57 182010 : if (!rootdse_dn) {
58 0 : talloc_free(tmp_ctx);
59 0 : return ldb_oom(ldb);
60 : }
61 :
62 182010 : ret = dsdb_module_search_dn(module, tmp_ctx, &rootdse_res, rootdse_dn,
63 : rootdse_attrs, DSDB_FLAG_NEXT_MODULE, parent);
64 182010 : if (ret != LDB_SUCCESS) {
65 6 : talloc_free(tmp_ctx);
66 6 : return ret;
67 : }
68 :
69 182004 : talloc_steal(mem_ctx, rootdse_res->msgs);
70 182004 : *msg = rootdse_res->msgs[0];
71 :
72 182004 : talloc_free(tmp_ctx);
73 :
74 182004 : return ret;
75 : }
76 :
77 364008 : static int prepare_modules_line(struct ldb_context *ldb,
78 : TALLOC_CTX *mem_ctx,
79 : const struct ldb_message *rootdse_msg,
80 : struct ldb_message *msg, const char *backend_attr,
81 : const char *backend_mod, const char **backend_mod_list)
82 : {
83 12032 : int ret;
84 12032 : const char **backend_full_list;
85 12032 : const char *backend_dn;
86 12032 : char *mod_list_string;
87 12032 : char *full_string;
88 364008 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
89 364008 : if (!tmp_ctx) {
90 0 : return ldb_oom(ldb);
91 : }
92 :
93 364008 : if (backend_attr) {
94 182004 : backend_dn = ldb_msg_find_attr_as_string(rootdse_msg, backend_attr, NULL);
95 182004 : if (!backend_dn) {
96 0 : ldb_asprintf_errstring(ldb,
97 : "samba_dsdb_init: "
98 : "unable to read %s from %s:%s",
99 0 : backend_attr, ldb_dn_get_linearized(rootdse_msg->dn),
100 : ldb_errstring(ldb));
101 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
102 : }
103 : } else {
104 175988 : backend_dn = "*";
105 : }
106 :
107 364008 : if (backend_mod) {
108 182004 : char **b = str_list_make_single(tmp_ctx, backend_mod);
109 182004 : backend_full_list = discard_const_p(const char *, b);
110 : } else {
111 182004 : char **b = str_list_make_empty(tmp_ctx);
112 182004 : backend_full_list = discard_const_p(const char *, b);
113 : }
114 364008 : if (!backend_full_list) {
115 0 : talloc_free(tmp_ctx);
116 0 : return ldb_oom(ldb);
117 : }
118 :
119 364008 : backend_full_list = str_list_append_const(backend_full_list, backend_mod_list);
120 364008 : if (!backend_full_list) {
121 0 : talloc_free(tmp_ctx);
122 0 : return ldb_oom(ldb);
123 : }
124 :
125 364008 : mod_list_string = str_list_join(tmp_ctx, backend_full_list, ',');
126 :
127 : /* str_list_append allocates on NULL */
128 364008 : talloc_free(backend_full_list);
129 :
130 364008 : if (!mod_list_string) {
131 0 : talloc_free(tmp_ctx);
132 0 : return ldb_oom(ldb);
133 : }
134 :
135 364008 : full_string = talloc_asprintf(tmp_ctx, "%s:%s", backend_dn, mod_list_string);
136 364008 : ret = ldb_msg_add_steal_string(msg, "modules", full_string);
137 364008 : talloc_free(tmp_ctx);
138 364008 : return ret;
139 : }
140 :
141 182005 : static bool check_required_features(struct ldb_message_element *el)
142 : {
143 182005 : if (el != NULL) {
144 5938 : int k;
145 167150 : DATA_BLOB esf = data_blob_string_const(
146 : SAMBA_ENCRYPTED_SECRETS_FEATURE);
147 167150 : DATA_BLOB lmdbl1 = data_blob_string_const(
148 : SAMBA_LMDB_LEVEL_ONE_FEATURE);
149 434170 : for (k = 0; k < el->num_values; k++) {
150 355016 : if ((data_blob_cmp(&esf, &el->values[k]) != 0) &&
151 93933 : (data_blob_cmp(&lmdbl1, &el->values[k]) != 0)) {
152 1 : return false;
153 : }
154 : }
155 : }
156 175988 : return true;
157 : }
158 :
159 182011 : static int samba_dsdb_init(struct ldb_module *module)
160 : {
161 182011 : struct ldb_context *ldb = ldb_module_get_ctx(module);
162 6017 : int ret, lock_ret, len, i, j;
163 182011 : TALLOC_CTX *tmp_ctx = talloc_new(module);
164 6017 : struct ldb_result *res;
165 182011 : struct ldb_message *rootdse_msg = NULL, *partition_msg;
166 6017 : struct ldb_dn *samba_dsdb_dn, *partition_dn, *indexlist_dn;
167 6017 : struct ldb_module *backend_module, *module_chain;
168 6017 : const char **final_module_list, **reverse_module_list;
169 : /*
170 : Add modules to the list to activate them by default
171 : beware often order is important
172 :
173 : Some Known ordering constraints:
174 : - rootdse must be first, as it makes redirects from "" -> cn=rootdse
175 : - extended_dn_in must be before objectclass.c, as it resolves the DN
176 : - objectclass must be before password_hash and samldb since these LDB
177 : modules require the expanded "objectClass" list
178 : - objectclass must be before descriptor and acl, as both assume that
179 : objectClass values are sorted
180 : - objectclass_attrs must be behind operational in order to see all
181 : attributes (the operational module protects and therefore
182 : suppresses per default some important ones)
183 : - partition must be last
184 : - each partition has its own module list then
185 :
186 : The list is presented here as a set of declarations to show the
187 : stack visually - the code below then handles the creation of the list
188 : based on the parameters loaded from the database.
189 : */
190 6017 : static const char *modules_list1[] = {"resolve_oids",
191 : "rootdse",
192 : "dsdb_notification",
193 : "schema_load",
194 : "lazy_commit",
195 : "dirsync",
196 : "dsdb_paged_results",
197 : "vlv",
198 : "ranged_results",
199 : "anr",
200 : "server_sort",
201 : "asq",
202 : "extended_dn_store",
203 : NULL };
204 : /* extended_dn_in or extended_dn_in_openldap goes here */
205 6017 : static const char *modules_list1a[] = {"audit_log",
206 : "objectclass",
207 : "tombstone_reanimate",
208 : "descriptor",
209 : "acl",
210 : "aclread",
211 : "samldb",
212 : "password_hash",
213 : "instancetype",
214 : "objectclass_attrs",
215 : NULL };
216 :
217 6017 : const char **link_modules;
218 6017 : static const char *tdb_modules_list[] = {
219 : "rdn_name",
220 : "subtree_delete",
221 : "repl_meta_data",
222 : "group_audit_log",
223 : "encrypted_secrets",
224 : "operational",
225 : "unique_object_sids",
226 : "subtree_rename",
227 : "linked_attributes",
228 : NULL};
229 :
230 6017 : const char *extended_dn_module;
231 182011 : const char *extended_dn_module_ldb = "extended_dn_out_ldb";
232 182011 : const char *extended_dn_in_module = "extended_dn_in";
233 :
234 6017 : static const char *modules_list2[] = {"dns_notify",
235 : "show_deleted",
236 : "new_partition",
237 : "partition",
238 : NULL };
239 :
240 6017 : const char **backend_modules;
241 6017 : static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR,
242 : SAMBA_REQUIRED_FEATURES_ATTR, NULL };
243 6017 : static const char *indexlist_attrs[] = { SAMBA_FEATURES_SUPPORTED_FLAG, NULL };
244 :
245 182011 : const char *current_supportedFeatures[] = {SAMBA_SORTED_LINKS_FEATURE};
246 :
247 182011 : if (!tmp_ctx) {
248 0 : return ldb_oom(ldb);
249 : }
250 :
251 182011 : ret = ldb_register_samba_handlers(ldb);
252 182011 : if (ret != LDB_SUCCESS) {
253 0 : talloc_free(tmp_ctx);
254 0 : return ret;
255 : }
256 :
257 182011 : samba_dsdb_dn = ldb_dn_new(tmp_ctx, ldb, "@SAMBA_DSDB");
258 182011 : if (!samba_dsdb_dn) {
259 0 : talloc_free(tmp_ctx);
260 0 : return ldb_oom(ldb);
261 : }
262 :
263 182011 : indexlist_dn = ldb_dn_new(tmp_ctx, ldb, "@INDEXLIST");
264 182011 : if (!samba_dsdb_dn) {
265 0 : talloc_free(tmp_ctx);
266 0 : return ldb_oom(ldb);
267 : }
268 :
269 182011 : partition_dn = ldb_dn_new(tmp_ctx, ldb, DSDB_PARTITION_DN);
270 182011 : if (!partition_dn) {
271 0 : talloc_free(tmp_ctx);
272 0 : return ldb_oom(ldb);
273 : }
274 :
275 : #define CHECK_LDB_RET(check_ret) \
276 : do { \
277 : if (check_ret != LDB_SUCCESS) { \
278 : talloc_free(tmp_ctx); \
279 : return check_ret; \
280 : } \
281 : } while (0)
282 :
283 182011 : ret = dsdb_module_search_dn(module, tmp_ctx, &res, samba_dsdb_dn,
284 : samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
285 182011 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
286 : /* do nothing, a very old db being upgraded */
287 182005 : } else if (ret == LDB_SUCCESS) {
288 6017 : struct ldb_message_element *requiredFeatures;
289 6017 : struct ldb_message_element *old_compatibleFeatures;
290 :
291 182005 : requiredFeatures = ldb_msg_find_element(res->msgs[0], SAMBA_REQUIRED_FEATURES_ATTR);
292 182005 : if (!check_required_features(requiredFeatures)) {
293 1 : ldb_set_errstring(
294 : ldb,
295 : "This Samba database was created with "
296 : "a newer Samba version and is marked "
297 : "with extra requiredFeatures in "
298 : "@SAMBA_DSDB. This database can not "
299 : "safely be read by this Samba version");
300 1 : return LDB_ERR_OPERATIONS_ERROR;
301 : }
302 :
303 182004 : old_compatibleFeatures = ldb_msg_find_element(res->msgs[0],
304 : SAMBA_COMPATIBLE_FEATURES_ATTR);
305 :
306 182004 : if (old_compatibleFeatures) {
307 5937 : struct ldb_message *features_msg;
308 5937 : struct ldb_message_element *features_el;
309 181696 : int samba_options_supported = 0;
310 181696 : ret = dsdb_module_search_dn(module, tmp_ctx, &res,
311 : indexlist_dn,
312 : indexlist_attrs,
313 : DSDB_FLAG_NEXT_MODULE, NULL);
314 181696 : if (ret == LDB_SUCCESS) {
315 5914 : samba_options_supported
316 181491 : = ldb_msg_find_attr_as_int(res->msgs[0],
317 : SAMBA_FEATURES_SUPPORTED_FLAG,
318 : 0);
319 :
320 205 : } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
321 : /*
322 : * If we don't have @INDEXLIST yet, then we
323 : * are so early in set-up that we know this is
324 : * a blank DB, so no need to wripe out old
325 : * features
326 : */
327 205 : samba_options_supported = 1;
328 : }
329 :
330 181696 : features_msg = ldb_msg_new(res);
331 181696 : if (features_msg == NULL) {
332 0 : return ldb_module_operr(module);
333 : }
334 181696 : features_msg->dn = samba_dsdb_dn;
335 :
336 181696 : ret = ldb_msg_add_empty(features_msg, SAMBA_COMPATIBLE_FEATURES_ATTR,
337 : LDB_FLAG_MOD_DELETE, &features_el);
338 181696 : if (ret != LDB_SUCCESS) {
339 0 : return ret;
340 : }
341 :
342 181696 : if (samba_options_supported == 1) {
343 175759 : for (i = 0;
344 363393 : old_compatibleFeatures && i < old_compatibleFeatures->num_values;
345 181697 : i++) {
346 175759 : for (j = 0;
347 181698 : j < ARRAY_SIZE(current_supportedFeatures); j++) {
348 181697 : if (strcmp((char *)old_compatibleFeatures->values[i].data,
349 : current_supportedFeatures[j]) == 0) {
350 175759 : break;
351 : }
352 : }
353 181697 : if (j == ARRAY_SIZE(current_supportedFeatures)) {
354 : /*
355 : * Add to list of features to remove
356 : * (rather than all features)
357 : */
358 2 : ret = ldb_msg_add_value(features_msg, SAMBA_COMPATIBLE_FEATURES_ATTR,
359 1 : &old_compatibleFeatures->values[i],
360 : NULL);
361 1 : if (ret != LDB_SUCCESS) {
362 0 : return ret;
363 : }
364 : }
365 : }
366 :
367 181696 : if (features_el->num_values > 0) {
368 : /* Delete by list */
369 1 : ret = ldb_next_start_trans(module);
370 1 : if (ret != LDB_SUCCESS) {
371 0 : return ret;
372 : }
373 1 : ret = dsdb_module_modify(module, features_msg, DSDB_FLAG_NEXT_MODULE, NULL);
374 1 : if (ret != LDB_SUCCESS) {
375 0 : ldb_next_del_trans(module);
376 0 : return ret;
377 : }
378 1 : ret = ldb_next_end_trans(module);
379 1 : if (ret != LDB_SUCCESS) {
380 0 : return ret;
381 : }
382 : }
383 : } else {
384 : /* Delete all */
385 0 : ret = ldb_next_start_trans(module);
386 0 : if (ret != LDB_SUCCESS) {
387 0 : return ret;
388 : }
389 0 : ret = dsdb_module_modify(module, features_msg, DSDB_FLAG_NEXT_MODULE, NULL);
390 0 : if (ret != LDB_SUCCESS) {
391 0 : ldb_next_del_trans(module);
392 0 : return ret;
393 : }
394 0 : ret = ldb_next_end_trans(module);
395 0 : if (ret != LDB_SUCCESS) {
396 0 : return ret;
397 : }
398 : }
399 : }
400 :
401 : } else {
402 0 : talloc_free(tmp_ctx);
403 0 : return ret;
404 : }
405 :
406 182010 : backend_modules = NULL;
407 182010 : extended_dn_module = extended_dn_module_ldb;
408 182010 : link_modules = tdb_modules_list;
409 :
410 : #define CHECK_MODULE_LIST \
411 : do { \
412 : if (!final_module_list) { \
413 : talloc_free(tmp_ctx); \
414 : return ldb_oom(ldb); \
415 : } \
416 : } while (0)
417 :
418 182010 : final_module_list = str_list_copy_const(tmp_ctx, modules_list1);
419 182010 : CHECK_MODULE_LIST;
420 :
421 182010 : final_module_list = str_list_add_const(final_module_list, extended_dn_in_module);
422 182010 : CHECK_MODULE_LIST;
423 :
424 182010 : final_module_list = str_list_append_const(final_module_list, modules_list1a);
425 182010 : CHECK_MODULE_LIST;
426 :
427 182010 : final_module_list = str_list_append_const(final_module_list, link_modules);
428 182010 : CHECK_MODULE_LIST;
429 :
430 182010 : final_module_list = str_list_add_const(final_module_list, extended_dn_module);
431 182010 : CHECK_MODULE_LIST;
432 :
433 182010 : final_module_list = str_list_append_const(final_module_list, modules_list2);
434 182010 : CHECK_MODULE_LIST;
435 :
436 :
437 182010 : ret = read_at_rootdse_record(ldb, module, tmp_ctx, &rootdse_msg, NULL);
438 182010 : CHECK_LDB_RET(ret);
439 :
440 182004 : partition_msg = ldb_msg_new(tmp_ctx);
441 182004 : partition_msg->dn = ldb_dn_new(partition_msg, ldb, "@" DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME);
442 :
443 182004 : ret = prepare_modules_line(ldb, tmp_ctx,
444 : rootdse_msg,
445 : partition_msg, "schemaNamingContext",
446 : "schema_data", backend_modules);
447 182004 : CHECK_LDB_RET(ret);
448 :
449 182004 : ret = prepare_modules_line(ldb, tmp_ctx,
450 : rootdse_msg,
451 : partition_msg, NULL,
452 : NULL, backend_modules);
453 182004 : CHECK_LDB_RET(ret);
454 :
455 182004 : ret = ldb_set_opaque(ldb, DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME, partition_msg);
456 182004 : CHECK_LDB_RET(ret);
457 :
458 182004 : talloc_steal(ldb, partition_msg);
459 :
460 : /* Now prepare the module chain. Oddly, we must give it to
461 : * ldb_module_load_list in REVERSE */
462 7104172 : for (len = 0; final_module_list[len]; len++) { /* noop */};
463 :
464 182004 : reverse_module_list = talloc_array(tmp_ctx, const char *, len+1);
465 182004 : if (!reverse_module_list) {
466 0 : talloc_free(tmp_ctx);
467 0 : return ldb_oom(ldb);
468 : }
469 7098156 : for (i=0; i < len; i++) {
470 6916152 : reverse_module_list[i] = final_module_list[(len - 1) - i];
471 : }
472 182004 : reverse_module_list[i] = NULL;
473 :
474 : /* The backend (at least until the partitions module
475 : * reconfigures things) is the next module in the currently
476 : * loaded chain */
477 182004 : backend_module = ldb_module_next(module);
478 182004 : ret = ldb_module_load_list(ldb, reverse_module_list, backend_module, &module_chain);
479 182004 : CHECK_LDB_RET(ret);
480 :
481 182004 : talloc_free(tmp_ctx);
482 : /* Set this as the 'next' module, so that we effectively append it to
483 : * module chain */
484 182004 : ldb_module_set_next(module, module_chain);
485 :
486 182004 : ret = ldb_next_read_lock(module);
487 182004 : if (ret != LDB_SUCCESS) {
488 0 : return ret;
489 : }
490 :
491 182004 : ret = ldb_next_init(module);
492 :
493 182004 : lock_ret = ldb_next_read_unlock(module);
494 :
495 182004 : if (lock_ret != LDB_SUCCESS) {
496 0 : return lock_ret;
497 : }
498 :
499 175988 : return ret;
500 : }
501 :
502 : static const struct ldb_module_ops ldb_samba_dsdb_module_ops = {
503 : .name = "samba_dsdb",
504 : .init_context = samba_dsdb_init,
505 : };
506 :
507 35 : static struct ldb_message *dsdb_flags_ignore_fixup(TALLOC_CTX *mem_ctx,
508 : const struct ldb_message *_msg)
509 : {
510 35 : struct ldb_message *msg = NULL;
511 35 : unsigned int i;
512 :
513 : /* we have to copy the message as the caller might have it as a const */
514 35 : msg = ldb_msg_copy_shallow(mem_ctx, _msg);
515 35 : if (msg == NULL) {
516 0 : return NULL;
517 : }
518 :
519 212 : for (i=0; i < msg->num_elements;) {
520 177 : struct ldb_message_element *e = &msg->elements[i];
521 :
522 177 : if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
523 165 : i++;
524 165 : continue;
525 : }
526 :
527 12 : e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
528 :
529 12 : if (e->num_values != 0) {
530 2 : i++;
531 2 : continue;
532 : }
533 :
534 10 : ldb_msg_remove_element(msg, e);
535 : }
536 :
537 0 : return msg;
538 : }
539 :
540 16 : static int dsdb_flags_ignore_add(struct ldb_module *module, struct ldb_request *req)
541 : {
542 16 : struct ldb_context *ldb = ldb_module_get_ctx(module);
543 16 : struct ldb_request *down_req = NULL;
544 16 : struct ldb_message *msg = NULL;
545 16 : int ret;
546 :
547 16 : msg = dsdb_flags_ignore_fixup(req, req->op.add.message);
548 16 : if (msg == NULL) {
549 0 : return ldb_module_oom(module);
550 : }
551 :
552 16 : ret = ldb_build_add_req(&down_req, ldb, req,
553 : msg,
554 : req->controls,
555 : req, dsdb_next_callback,
556 : req);
557 16 : LDB_REQ_SET_LOCATION(down_req);
558 16 : if (ret != LDB_SUCCESS) {
559 0 : return ret;
560 : }
561 :
562 : /* go on with the call chain */
563 16 : return ldb_next_request(module, down_req);
564 : }
565 :
566 19 : static int dsdb_flags_ignore_modify(struct ldb_module *module, struct ldb_request *req)
567 : {
568 19 : struct ldb_context *ldb = ldb_module_get_ctx(module);
569 19 : struct ldb_request *down_req = NULL;
570 19 : struct ldb_message *msg = NULL;
571 19 : int ret;
572 :
573 19 : msg = dsdb_flags_ignore_fixup(req, req->op.mod.message);
574 19 : if (msg == NULL) {
575 0 : return ldb_module_oom(module);
576 : }
577 :
578 19 : ret = ldb_build_mod_req(&down_req, ldb, req,
579 : msg,
580 : req->controls,
581 : req, dsdb_next_callback,
582 : req);
583 19 : LDB_REQ_SET_LOCATION(down_req);
584 19 : if (ret != LDB_SUCCESS) {
585 0 : return ret;
586 : }
587 :
588 : /* go on with the call chain */
589 19 : return ldb_next_request(module, down_req);
590 : }
591 :
592 : static const struct ldb_module_ops ldb_dsdb_flags_ignore_module_ops = {
593 : .name = "dsdb_flags_ignore",
594 : .add = dsdb_flags_ignore_add,
595 : .modify = dsdb_flags_ignore_modify,
596 : };
597 :
598 6040 : int ldb_samba_dsdb_module_init(const char *version)
599 : {
600 444 : int ret;
601 6040 : LDB_MODULE_CHECK_VERSION(version);
602 6040 : ret = ldb_register_module(&ldb_samba_dsdb_module_ops);
603 6040 : if (ret != LDB_SUCCESS) {
604 0 : return ret;
605 : }
606 6040 : ret = ldb_register_module(&ldb_dsdb_flags_ignore_module_ops);
607 6040 : if (ret != LDB_SUCCESS) {
608 0 : return ret;
609 : }
610 5596 : return LDB_SUCCESS;
611 : }
|