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 181595 : 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 6078 : int ret;
48 6078 : static const char *rootdse_attrs[] = { "defaultNamingContext", "configurationNamingContext", "schemaNamingContext", NULL };
49 6078 : struct ldb_result *rootdse_res;
50 6078 : struct ldb_dn *rootdse_dn;
51 181595 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
52 181595 : if (!tmp_ctx) {
53 0 : return ldb_oom(ldb);
54 : }
55 :
56 181595 : rootdse_dn = ldb_dn_new(tmp_ctx, ldb, "@ROOTDSE");
57 181595 : if (!rootdse_dn) {
58 0 : talloc_free(tmp_ctx);
59 0 : return ldb_oom(ldb);
60 : }
61 :
62 181595 : ret = dsdb_module_search_dn(module, tmp_ctx, &rootdse_res, rootdse_dn,
63 : rootdse_attrs, DSDB_FLAG_NEXT_MODULE, parent);
64 181595 : if (ret != LDB_SUCCESS) {
65 6 : talloc_free(tmp_ctx);
66 6 : return ret;
67 : }
68 :
69 181589 : talloc_steal(mem_ctx, rootdse_res->msgs);
70 181589 : *msg = rootdse_res->msgs[0];
71 :
72 181589 : talloc_free(tmp_ctx);
73 :
74 181589 : return ret;
75 : }
76 :
77 363178 : 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 12156 : int ret;
84 12156 : const char **backend_full_list;
85 12156 : const char *backend_dn;
86 12156 : char *mod_list_string;
87 12156 : char *full_string;
88 363178 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
89 363178 : if (!tmp_ctx) {
90 0 : return ldb_oom(ldb);
91 : }
92 :
93 363178 : if (backend_attr) {
94 181589 : backend_dn = ldb_msg_find_attr_as_string(rootdse_msg, backend_attr, NULL);
95 181589 : 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 175511 : backend_dn = "*";
105 : }
106 :
107 363178 : if (backend_mod) {
108 181589 : char **b = str_list_make_single(tmp_ctx, backend_mod);
109 181589 : backend_full_list = discard_const_p(const char *, b);
110 : } else {
111 181589 : char **b = str_list_make_empty(tmp_ctx);
112 181589 : backend_full_list = discard_const_p(const char *, b);
113 : }
114 363178 : if (!backend_full_list) {
115 0 : talloc_free(tmp_ctx);
116 0 : return ldb_oom(ldb);
117 : }
118 :
119 363178 : backend_full_list = str_list_append_const(backend_full_list, backend_mod_list);
120 363178 : if (!backend_full_list) {
121 0 : talloc_free(tmp_ctx);
122 0 : return ldb_oom(ldb);
123 : }
124 :
125 363178 : mod_list_string = str_list_join(tmp_ctx, backend_full_list, ',');
126 :
127 : /* str_list_append allocates on NULL */
128 363178 : talloc_free(backend_full_list);
129 :
130 363178 : if (!mod_list_string) {
131 0 : talloc_free(tmp_ctx);
132 0 : return ldb_oom(ldb);
133 : }
134 :
135 363178 : full_string = talloc_asprintf(tmp_ctx, "%s:%s", backend_dn, mod_list_string);
136 363178 : ret = ldb_msg_add_steal_string(msg, "modules", full_string);
137 363178 : talloc_free(tmp_ctx);
138 363178 : return ret;
139 : }
140 :
141 181590 : static bool check_required_features(struct ldb_message_element *el)
142 : {
143 181590 : if (el != NULL) {
144 6000 : int k;
145 167132 : DATA_BLOB esf = data_blob_string_const(
146 : SAMBA_ENCRYPTED_SECRETS_FEATURE);
147 167132 : DATA_BLOB lmdbl1 = data_blob_string_const(
148 : SAMBA_LMDB_LEVEL_ONE_FEATURE);
149 434500 : for (k = 0; k < el->num_values; k++) {
150 355606 : if ((data_blob_cmp(&esf, &el->values[k]) != 0) &&
151 94237 : (data_blob_cmp(&lmdbl1, &el->values[k]) != 0)) {
152 1 : return false;
153 : }
154 : }
155 : }
156 175511 : return true;
157 : }
158 :
159 181596 : static int samba_dsdb_init(struct ldb_module *module)
160 : {
161 181596 : struct ldb_context *ldb = ldb_module_get_ctx(module);
162 6079 : int ret, lock_ret, len, i, j;
163 181596 : TALLOC_CTX *tmp_ctx = talloc_new(module);
164 6079 : struct ldb_result *res;
165 181596 : struct ldb_message *rootdse_msg = NULL, *partition_msg;
166 6079 : struct ldb_dn *samba_dsdb_dn, *partition_dn, *indexlist_dn;
167 6079 : struct ldb_module *backend_module, *module_chain;
168 6079 : 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 6079 : 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 6079 : 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 6079 : const char **link_modules;
218 6079 : 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 6079 : const char *extended_dn_module;
231 181596 : const char *extended_dn_module_ldb = "extended_dn_out_ldb";
232 181596 : const char *extended_dn_in_module = "extended_dn_in";
233 :
234 6079 : static const char *modules_list2[] = {"dns_notify",
235 : "show_deleted",
236 : "new_partition",
237 : "partition",
238 : NULL };
239 :
240 6079 : const char **backend_modules;
241 6079 : static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR,
242 : SAMBA_REQUIRED_FEATURES_ATTR, NULL };
243 6079 : static const char *indexlist_attrs[] = { SAMBA_FEATURES_SUPPORTED_FLAG, NULL };
244 :
245 181596 : const char *current_supportedFeatures[] = {SAMBA_SORTED_LINKS_FEATURE};
246 :
247 181596 : if (!tmp_ctx) {
248 0 : return ldb_oom(ldb);
249 : }
250 :
251 181596 : ret = ldb_register_samba_handlers(ldb);
252 181596 : if (ret != LDB_SUCCESS) {
253 0 : talloc_free(tmp_ctx);
254 0 : return ret;
255 : }
256 :
257 181596 : samba_dsdb_dn = ldb_dn_new(tmp_ctx, ldb, "@SAMBA_DSDB");
258 181596 : if (!samba_dsdb_dn) {
259 0 : talloc_free(tmp_ctx);
260 0 : return ldb_oom(ldb);
261 : }
262 :
263 181596 : indexlist_dn = ldb_dn_new(tmp_ctx, ldb, "@INDEXLIST");
264 181596 : if (!samba_dsdb_dn) {
265 0 : talloc_free(tmp_ctx);
266 0 : return ldb_oom(ldb);
267 : }
268 :
269 181596 : partition_dn = ldb_dn_new(tmp_ctx, ldb, DSDB_PARTITION_DN);
270 181596 : 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 181596 : ret = dsdb_module_search_dn(module, tmp_ctx, &res, samba_dsdb_dn,
284 : samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
285 181596 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
286 : /* do nothing, a very old db being upgraded */
287 181590 : } else if (ret == LDB_SUCCESS) {
288 6079 : struct ldb_message_element *requiredFeatures;
289 6079 : struct ldb_message_element *old_compatibleFeatures;
290 :
291 181590 : requiredFeatures = ldb_msg_find_element(res->msgs[0], SAMBA_REQUIRED_FEATURES_ATTR);
292 181590 : 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 181589 : old_compatibleFeatures = ldb_msg_find_element(res->msgs[0],
304 : SAMBA_COMPATIBLE_FEATURES_ATTR);
305 :
306 181589 : if (old_compatibleFeatures) {
307 5999 : struct ldb_message *features_msg;
308 5999 : struct ldb_message_element *features_el;
309 181281 : int samba_options_supported = 0;
310 181281 : ret = dsdb_module_search_dn(module, tmp_ctx, &res,
311 : indexlist_dn,
312 : indexlist_attrs,
313 : DSDB_FLAG_NEXT_MODULE, NULL);
314 181281 : if (ret == LDB_SUCCESS) {
315 5976 : samba_options_supported
316 181076 : = 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 181281 : features_msg = ldb_msg_new(res);
331 181281 : if (features_msg == NULL) {
332 0 : return ldb_module_operr(module);
333 : }
334 181281 : features_msg->dn = samba_dsdb_dn;
335 :
336 181281 : ret = ldb_msg_add_empty(features_msg, SAMBA_COMPATIBLE_FEATURES_ATTR,
337 : LDB_FLAG_MOD_DELETE, &features_el);
338 181281 : if (ret != LDB_SUCCESS) {
339 0 : return ret;
340 : }
341 :
342 181281 : if (samba_options_supported == 1) {
343 175282 : for (i = 0;
344 362563 : old_compatibleFeatures && i < old_compatibleFeatures->num_values;
345 181282 : i++) {
346 175282 : for (j = 0;
347 181283 : j < ARRAY_SIZE(current_supportedFeatures); j++) {
348 181282 : if (strcmp((char *)old_compatibleFeatures->values[i].data,
349 : current_supportedFeatures[j]) == 0) {
350 175282 : break;
351 : }
352 : }
353 181282 : 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 181281 : 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 181595 : backend_modules = NULL;
407 181595 : extended_dn_module = extended_dn_module_ldb;
408 181595 : 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 181595 : final_module_list = str_list_copy_const(tmp_ctx, modules_list1);
419 181595 : CHECK_MODULE_LIST;
420 :
421 181595 : final_module_list = str_list_add_const(final_module_list, extended_dn_in_module);
422 181595 : CHECK_MODULE_LIST;
423 :
424 181595 : final_module_list = str_list_append_const(final_module_list, modules_list1a);
425 181595 : CHECK_MODULE_LIST;
426 :
427 181595 : final_module_list = str_list_append_const(final_module_list, link_modules);
428 181595 : CHECK_MODULE_LIST;
429 :
430 181595 : final_module_list = str_list_add_const(final_module_list, extended_dn_module);
431 181595 : CHECK_MODULE_LIST;
432 :
433 181595 : final_module_list = str_list_append_const(final_module_list, modules_list2);
434 181595 : CHECK_MODULE_LIST;
435 :
436 :
437 181595 : ret = read_at_rootdse_record(ldb, module, tmp_ctx, &rootdse_msg, NULL);
438 181595 : CHECK_LDB_RET(ret);
439 :
440 181589 : partition_msg = ldb_msg_new(tmp_ctx);
441 181589 : partition_msg->dn = ldb_dn_new(partition_msg, ldb, "@" DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME);
442 :
443 181589 : ret = prepare_modules_line(ldb, tmp_ctx,
444 : rootdse_msg,
445 : partition_msg, "schemaNamingContext",
446 : "schema_data", backend_modules);
447 181589 : CHECK_LDB_RET(ret);
448 :
449 181589 : ret = prepare_modules_line(ldb, tmp_ctx,
450 : rootdse_msg,
451 : partition_msg, NULL,
452 : NULL, backend_modules);
453 181589 : CHECK_LDB_RET(ret);
454 :
455 : /* This opaque is also used by the gMSA code to confirm that it has local DB access */
456 181589 : ret = ldb_set_opaque(ldb, DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME, partition_msg);
457 181589 : CHECK_LDB_RET(ret);
458 :
459 181589 : talloc_steal(ldb, partition_msg);
460 :
461 : /* Now prepare the module chain. Oddly, we must give it to
462 : * ldb_module_load_list in REVERSE */
463 7088049 : for (len = 0; final_module_list[len]; len++) { /* noop */};
464 :
465 181589 : reverse_module_list = talloc_array(tmp_ctx, const char *, len+1);
466 181589 : if (!reverse_module_list) {
467 0 : talloc_free(tmp_ctx);
468 0 : return ldb_oom(ldb);
469 : }
470 7081971 : for (i=0; i < len; i++) {
471 6900382 : reverse_module_list[i] = final_module_list[(len - 1) - i];
472 : }
473 181589 : reverse_module_list[i] = NULL;
474 :
475 : /* The backend (at least until the partitions module
476 : * reconfigures things) is the next module in the currently
477 : * loaded chain */
478 181589 : backend_module = ldb_module_next(module);
479 181589 : ret = ldb_module_load_list(ldb, reverse_module_list, backend_module, &module_chain);
480 181589 : CHECK_LDB_RET(ret);
481 :
482 181589 : talloc_free(tmp_ctx);
483 : /* Set this as the 'next' module, so that we effectively append it to
484 : * module chain */
485 181589 : ldb_module_set_next(module, module_chain);
486 :
487 181589 : ret = ldb_next_read_lock(module);
488 181589 : if (ret != LDB_SUCCESS) {
489 0 : return ret;
490 : }
491 :
492 181589 : ret = ldb_next_init(module);
493 :
494 181589 : lock_ret = ldb_next_read_unlock(module);
495 :
496 181589 : if (lock_ret != LDB_SUCCESS) {
497 0 : return lock_ret;
498 : }
499 :
500 175511 : return ret;
501 : }
502 :
503 : static const struct ldb_module_ops ldb_samba_dsdb_module_ops = {
504 : .name = "samba_dsdb",
505 : .init_context = samba_dsdb_init,
506 : };
507 :
508 35 : static struct ldb_message *dsdb_flags_ignore_fixup(TALLOC_CTX *mem_ctx,
509 : const struct ldb_message *_msg)
510 : {
511 35 : struct ldb_message *msg = NULL;
512 35 : unsigned int i;
513 :
514 : /* we have to copy the message as the caller might have it as a const */
515 35 : msg = ldb_msg_copy_shallow(mem_ctx, _msg);
516 35 : if (msg == NULL) {
517 0 : return NULL;
518 : }
519 :
520 212 : for (i=0; i < msg->num_elements;) {
521 177 : struct ldb_message_element *e = &msg->elements[i];
522 :
523 177 : if (!(e->flags & DSDB_FLAG_INTERNAL_FORCE_META_DATA)) {
524 165 : i++;
525 165 : continue;
526 : }
527 :
528 12 : e->flags &= ~DSDB_FLAG_INTERNAL_FORCE_META_DATA;
529 :
530 12 : if (e->num_values != 0) {
531 2 : i++;
532 2 : continue;
533 : }
534 :
535 10 : ldb_msg_remove_element(msg, e);
536 : }
537 :
538 0 : return msg;
539 : }
540 :
541 16 : static int dsdb_flags_ignore_add(struct ldb_module *module, struct ldb_request *req)
542 : {
543 16 : struct ldb_context *ldb = ldb_module_get_ctx(module);
544 16 : struct ldb_request *down_req = NULL;
545 16 : struct ldb_message *msg = NULL;
546 16 : int ret;
547 :
548 16 : msg = dsdb_flags_ignore_fixup(req, req->op.add.message);
549 16 : if (msg == NULL) {
550 0 : return ldb_module_oom(module);
551 : }
552 :
553 16 : ret = ldb_build_add_req(&down_req, ldb, req,
554 : msg,
555 : req->controls,
556 : req, dsdb_next_callback,
557 : req);
558 16 : LDB_REQ_SET_LOCATION(down_req);
559 16 : if (ret != LDB_SUCCESS) {
560 0 : return ret;
561 : }
562 :
563 : /* go on with the call chain */
564 16 : return ldb_next_request(module, down_req);
565 : }
566 :
567 19 : static int dsdb_flags_ignore_modify(struct ldb_module *module, struct ldb_request *req)
568 : {
569 19 : struct ldb_context *ldb = ldb_module_get_ctx(module);
570 19 : struct ldb_request *down_req = NULL;
571 19 : struct ldb_message *msg = NULL;
572 19 : int ret;
573 :
574 19 : msg = dsdb_flags_ignore_fixup(req, req->op.mod.message);
575 19 : if (msg == NULL) {
576 0 : return ldb_module_oom(module);
577 : }
578 :
579 19 : ret = ldb_build_mod_req(&down_req, ldb, req,
580 : msg,
581 : req->controls,
582 : req, dsdb_next_callback,
583 : req);
584 19 : LDB_REQ_SET_LOCATION(down_req);
585 19 : if (ret != LDB_SUCCESS) {
586 0 : return ret;
587 : }
588 :
589 : /* go on with the call chain */
590 19 : return ldb_next_request(module, down_req);
591 : }
592 :
593 : static const struct ldb_module_ops ldb_dsdb_flags_ignore_module_ops = {
594 : .name = "dsdb_flags_ignore",
595 : .add = dsdb_flags_ignore_add,
596 : .modify = dsdb_flags_ignore_modify,
597 : };
598 :
599 6286 : int ldb_samba_dsdb_module_init(const char *version)
600 : {
601 445 : int ret;
602 6286 : LDB_MODULE_CHECK_VERSION(version);
603 6286 : ret = ldb_register_module(&ldb_samba_dsdb_module_ops);
604 6286 : if (ret != LDB_SUCCESS) {
605 0 : return ret;
606 : }
607 6286 : ret = ldb_register_module(&ldb_dsdb_flags_ignore_module_ops);
608 6286 : if (ret != LDB_SUCCESS) {
609 0 : return ret;
610 : }
611 5841 : return LDB_SUCCESS;
612 : }
|