1 /*
2 * lmdb backend specific tests for ldb
3 *
4 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
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 /*
22 * lmdb backend specific tests for ldb
23 *
24 * Setup and tear down code copied from ldb_mod_op_test.c
25 */
26
27 /*
28 * from cmocka.c:
29 * These headers or their equivalents should be included prior to
30 * including
31 * this header file.
32 *
33 * #include <stdarg.h>
34 * #include <stddef.h>
35 * #include <setjmp.h>
36 *
37 * This allows test applications to use custom definitions of C standard
38 * library functions and types.
39 *
40 */
41 #include <stdarg.h>
42 #include <stddef.h>
43 #include <stdint.h>
44 #include <setjmp.h>
45 #include <cmocka.h>
46
47 #include <errno.h>
48 #include <unistd.h>
49 #include <talloc.h>
50 #include <tevent.h>
51 #include <ldb.h>
52 #include <ldb_module.h>
53 #include <ldb_private.h>
54 #include <string.h>
55 #include <ctype.h>
56
57 #include <sys/wait.h>
58
59 #include "../ldb_tdb/ldb_tdb.h"
60 #include "../ldb_mdb/ldb_mdb.h"
61 #include "../ldb_key_value/ldb_kv.h"
62
63 #define TEST_BE "mdb"
64
65 #define LMDB_MAX_KEY_SIZE 511
66
67 struct ldbtest_ctx {
68 struct tevent_context *ev;
69 struct ldb_context *ldb;
70
71 const char *dbfile;
72 const char *lockfile; /* lockfile is separate */
73
74 const char *dbpath;
75 };
76
unlink_old_db(struct ldbtest_ctx * test_ctx)77 static void unlink_old_db(struct ldbtest_ctx *test_ctx)
78 {
79 int ret;
80
81 errno = 0;
82 ret = unlink(test_ctx->lockfile);
83 if (ret == -1 && errno != ENOENT) {
84 fail();
85 }
86
87 errno = 0;
88 ret = unlink(test_ctx->dbfile);
89 if (ret == -1 && errno != ENOENT) {
90 fail();
91 }
92 }
93
ldbtest_noconn_setup(void ** state)94 static int ldbtest_noconn_setup(void **state)
95 {
96 struct ldbtest_ctx *test_ctx;
97
98 test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
99 assert_non_null(test_ctx);
100
101 test_ctx->ev = tevent_context_init(test_ctx);
102 assert_non_null(test_ctx->ev);
103
104 test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
105 assert_non_null(test_ctx->ldb);
106
107 test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
108 assert_non_null(test_ctx->dbfile);
109
110 test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
111 test_ctx->dbfile);
112 assert_non_null(test_ctx->lockfile);
113
114 test_ctx->dbpath = talloc_asprintf(test_ctx,
115 TEST_BE"://%s", test_ctx->dbfile);
116 assert_non_null(test_ctx->dbpath);
117
118 unlink_old_db(test_ctx);
119 *state = test_ctx;
120 return 0;
121 }
122
ldbtest_noconn_teardown(void ** state)123 static int ldbtest_noconn_teardown(void **state)
124 {
125 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
126 struct ldbtest_ctx);
127
128 unlink_old_db(test_ctx);
129 talloc_free(test_ctx);
130 return 0;
131 }
132
ldbtest_setup(void ** state)133 static int ldbtest_setup(void **state)
134 {
135 struct ldbtest_ctx *test_ctx;
136 int ret;
137 struct ldb_ldif *ldif;
138 const char *index_ldif = \
139 "dn: @INDEXLIST\n"
140 "@IDXGUID: objectUUID\n"
141 "@IDX_DN_GUID: GUID\n"
142 "\n";
143
144 ldbtest_noconn_setup((void **) &test_ctx);
145
146 ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
147 assert_int_equal(ret, 0);
148
149 while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
150 ret = ldb_add(test_ctx->ldb, ldif->msg);
151 assert_int_equal(ret, LDB_SUCCESS);
152 }
153 *state = test_ctx;
154 return 0;
155 }
156
ldbtest_teardown(void ** state)157 static int ldbtest_teardown(void **state)
158 {
159 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
160 struct ldbtest_ctx);
161 ldbtest_noconn_teardown((void **) &test_ctx);
162 return 0;
163 }
164
test_ldb_add_key_len_gt_max(void ** state)165 static void test_ldb_add_key_len_gt_max(void **state)
166 {
167 int ret;
168 int xs_size = 0;
169 struct ldb_message *msg;
170 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
171 struct ldbtest_ctx);
172 char *xs = NULL;
173 TALLOC_CTX *tmp_ctx;
174
175 tmp_ctx = talloc_new(test_ctx);
176 assert_non_null(tmp_ctx);
177
178 msg = ldb_msg_new(tmp_ctx);
179 assert_non_null(msg);
180
181 /*
182 * The zero terminator is part of the key if we were not in
183 * GUID mode
184 */
185
186 xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */
187 xs_size += 1; /* want key on char too long */
188 xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
189 memset(xs, 'x', xs_size);
190
191 msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
192 assert_non_null(msg->dn);
193
194 ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
195 assert_int_equal(ret, 0);
196
197 ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
198 assert_int_equal(ret, 0);
199
200 ret = ldb_add(test_ctx->ldb, msg);
201 assert_int_equal(ret, LDB_SUCCESS);
202
203 talloc_free(tmp_ctx);
204 }
205
test_ldb_add_key_len_2x_gt_max(void ** state)206 static void test_ldb_add_key_len_2x_gt_max(void **state)
207 {
208 int ret;
209 int xs_size = 0;
210 struct ldb_message *msg;
211 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
212 struct ldbtest_ctx);
213 char *xs = NULL;
214 TALLOC_CTX *tmp_ctx;
215
216 tmp_ctx = talloc_new(test_ctx);
217 assert_non_null(tmp_ctx);
218
219 msg = ldb_msg_new(tmp_ctx);
220 assert_non_null(msg);
221
222 /*
223 * The zero terminator is part of the key if we were not in
224 * GUID mode
225 */
226
227 xs_size = 2 * LMDB_MAX_KEY_SIZE;
228 xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
229 memset(xs, 'x', xs_size);
230
231 msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
232 assert_non_null(msg->dn);
233
234 ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
235 assert_int_equal(ret, 0);
236
237 ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
238 assert_int_equal(ret, 0);
239
240 ret = ldb_add(test_ctx->ldb, msg);
241 assert_int_equal(ret, LDB_SUCCESS);
242
243 talloc_free(tmp_ctx);
244 }
245
test_ldb_add_key_len_eq_max(void ** state)246 static void test_ldb_add_key_len_eq_max(void **state)
247 {
248 int ret;
249 int xs_size = 0;
250 struct ldb_message *msg;
251 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
252 struct ldbtest_ctx);
253 char *xs = NULL;
254 TALLOC_CTX *tmp_ctx;
255
256 tmp_ctx = talloc_new(test_ctx);
257 assert_non_null(tmp_ctx);
258
259 msg = ldb_msg_new(tmp_ctx);
260 assert_non_null(msg);
261
262 /*
263 * The zero terminator is part of the key if we were not in
264 * GUID mode
265 */
266
267 xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */
268 xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
269 memset(xs, 'x', xs_size);
270
271 msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
272 assert_non_null(msg->dn);
273
274 ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
275 assert_int_equal(ret, 0);
276
277 ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
278 assert_int_equal(ret, 0);
279
280 ret = ldb_add(test_ctx->ldb, msg);
281 assert_int_equal(ret, 0);
282
283 talloc_free(tmp_ctx);
284 }
285
ldbtest_setup_noguid(void ** state)286 static int ldbtest_setup_noguid(void **state)
287 {
288 struct ldbtest_ctx *test_ctx;
289 int ret;
290
291 ldbtest_noconn_setup((void **) &test_ctx);
292
293 ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
294 assert_int_equal(ret, 0);
295
296 *state = test_ctx;
297 return 0;
298 }
299
test_ldb_add_special_key_len_gt_max(void ** state)300 static void test_ldb_add_special_key_len_gt_max(void **state)
301 {
302 int ret;
303 int xs_size = 0;
304 struct ldb_message *msg;
305 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
306 struct ldbtest_ctx);
307 char *xs = NULL;
308 TALLOC_CTX *tmp_ctx;
309
310 tmp_ctx = talloc_new(test_ctx);
311 assert_non_null(tmp_ctx);
312
313 msg = ldb_msg_new(tmp_ctx);
314 assert_non_null(msg);
315
316 /*
317 * The zero terminator is part of the key if we were not in
318 * GUID mode
319 */
320
321 xs_size = LMDB_MAX_KEY_SIZE - 5; /* "dn=@" and the zero terminator */
322 xs_size += 1; /* want key on char too long */
323 xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
324 memset(xs, 'x', xs_size);
325
326 msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "@%s", xs);
327 assert_non_null(msg->dn);
328
329 ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
330 assert_int_equal(ret, 0);
331
332 ret = ldb_add(test_ctx->ldb, msg);
333 assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
334
335 talloc_free(tmp_ctx);
336 }
337
test_ldb_add_special_key_len_eq_max(void ** state)338 static void test_ldb_add_special_key_len_eq_max(void **state)
339 {
340 int ret;
341 int xs_size = 0;
342 struct ldb_message *msg;
343 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
344 struct ldbtest_ctx);
345 char *xs = NULL;
346 TALLOC_CTX *tmp_ctx;
347
348 tmp_ctx = talloc_new(test_ctx);
349 assert_non_null(tmp_ctx);
350
351 msg = ldb_msg_new(tmp_ctx);
352 assert_non_null(msg);
353
354 /*
355 * The zero terminator is part of the key if we were not in
356 * GUID mode
357 */
358
359 xs_size = LMDB_MAX_KEY_SIZE - 5; /* "dn=@" and the zero terminator */
360 xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
361 memset(xs, 'x', xs_size);
362
363 msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "@%s", xs);
364 assert_non_null(msg->dn);
365
366 ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
367 assert_int_equal(ret, 0);
368
369 ret = ldb_add(test_ctx->ldb, msg);
370 assert_int_equal(ret, LDB_SUCCESS);
371
372 talloc_free(tmp_ctx);
373 }
374
test_ldb_add_dn_no_guid_mode(void ** state)375 static void test_ldb_add_dn_no_guid_mode(void **state)
376 {
377 int ret;
378 int xs_size = 0;
379 struct ldb_message *msg;
380 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
381 struct ldbtest_ctx);
382 char *xs = NULL;
383 TALLOC_CTX *tmp_ctx;
384
385 tmp_ctx = talloc_new(test_ctx);
386 assert_non_null(tmp_ctx);
387
388 msg = ldb_msg_new(tmp_ctx);
389 assert_non_null(msg);
390
391 /*
392 * The zero terminator is part of the key if we were not in
393 * GUID mode
394 */
395
396 xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */
397 xs_size += 1; /* want key on char too long */
398 xs = talloc_zero_size(tmp_ctx, (xs_size + 1));
399 memset(xs, 'x', xs_size);
400
401 msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs);
402 assert_non_null(msg->dn);
403
404 ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
405 assert_int_equal(ret, 0);
406
407 ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
408 assert_int_equal(ret, 0);
409
410 ret = ldb_add(test_ctx->ldb, msg);
411 assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
412
413 talloc_free(tmp_ctx);
414 }
415
get_mdb_env(struct ldb_context * ldb)416 static struct MDB_env *get_mdb_env(struct ldb_context *ldb)
417 {
418 void *data = NULL;
419 struct ldb_kv_private *ldb_kv = NULL;
420 struct lmdb_private *lmdb = NULL;
421 struct MDB_env *env = NULL;
422
423 data = ldb_module_get_private(ldb->modules);
424 assert_non_null(data);
425
426 ldb_kv = talloc_get_type(data, struct ldb_kv_private);
427 assert_non_null(ldb_kv);
428
429 lmdb = ldb_kv->lmdb_private;
430 assert_non_null(lmdb);
431
432 env = lmdb->env;
433 assert_non_null(env);
434
435 return env;
436 }
437
test_multiple_opens(void ** state)438 static void test_multiple_opens(void **state)
439 {
440 struct ldb_context *ldb1 = NULL;
441 struct ldb_context *ldb2 = NULL;
442 struct ldb_context *ldb3 = NULL;
443 struct MDB_env *env1 = NULL;
444 struct MDB_env *env2 = NULL;
445 struct MDB_env *env3 = NULL;
446 int ret;
447 struct ldbtest_ctx *test_ctx = NULL;
448
449 test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
450
451 /*
452 * Open the database again
453 */
454 ldb1 = ldb_init(test_ctx, test_ctx->ev);
455 ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
456 assert_int_equal(ret, 0);
457
458 ldb2 = ldb_init(test_ctx, test_ctx->ev);
459 ret = ldb_connect(ldb2, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
460 assert_int_equal(ret, 0);
461
462 ldb3 = ldb_init(test_ctx, test_ctx->ev);
463 ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
464 assert_int_equal(ret, 0);
465 /*
466 * We now have 3 ldb's open pointing to the same on disk database
467 * they should all share the same MDB_env
468 */
469 env1 = get_mdb_env(ldb1);
470 env2 = get_mdb_env(ldb2);
471 env3 = get_mdb_env(ldb3);
472
473 assert_ptr_equal(env1, env2);
474 assert_ptr_equal(env1, env3);
475 }
476
test_multiple_opens_across_fork(void ** state)477 static void test_multiple_opens_across_fork(void **state)
478 {
479 struct ldb_context *ldb1 = NULL;
480 struct ldb_context *ldb2 = NULL;
481 struct MDB_env *env1 = NULL;
482 struct MDB_env *env2 = NULL;
483 int ret;
484 struct ldbtest_ctx *test_ctx = NULL;
485 int pipes[2];
486 char buf[2];
487 int wstatus;
488 pid_t pid, child_pid;
489
490 test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
491
492 /*
493 * Open the database again
494 */
495 ldb1 = ldb_init(test_ctx, test_ctx->ev);
496 ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
497 assert_int_equal(ret, 0);
498
499 ldb2 = ldb_init(test_ctx, test_ctx->ev);
500 ret = ldb_connect(ldb2, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
501 assert_int_equal(ret, 0);
502
503 env1 = get_mdb_env(ldb1);
504 env2 = get_mdb_env(ldb2);
505
506 ret = pipe(pipes);
507 assert_int_equal(ret, 0);
508
509 child_pid = fork();
510 if (child_pid == 0) {
511 struct ldb_context *ldb3 = NULL;
512 struct MDB_env *env3 = NULL;
513
514 close(pipes[0]);
515 ldb3 = ldb_init(test_ctx, test_ctx->ev);
516 ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
517 if (ret != 0) {
518 print_error(__location__": ldb_connect returned (%d)\n",
519 ret);
520 exit(ret);
521 }
522 env3 = get_mdb_env(ldb3);
523 if (env1 != env2) {
524 print_error(__location__": env1 != env2\n");
525 exit(LDB_ERR_OPERATIONS_ERROR);
526 }
527 if (env1 == env3) {
528 print_error(__location__": env1 == env3\n");
529 exit(LDB_ERR_OPERATIONS_ERROR);
530 }
531 ret = write(pipes[1], "GO", 2);
532 if (ret != 2) {
533 print_error(__location__
534 " write returned (%d)",
535 ret);
536 exit(LDB_ERR_OPERATIONS_ERROR);
537 }
538 exit(LDB_SUCCESS);
539 }
540 close(pipes[1]);
541 ret = read(pipes[0], buf, 2);
542 assert_int_equal(ret, 2);
543
544 pid = waitpid(child_pid, &wstatus, 0);
545 assert_int_equal(pid, child_pid);
546
547 assert_true(WIFEXITED(wstatus));
548
549 assert_int_equal(WEXITSTATUS(wstatus), 0);
550 }
551
main(int argc,const char ** argv)552 int main(int argc, const char **argv)
553 {
554 const struct CMUnitTest tests[] = {
555 cmocka_unit_test_setup_teardown(
556 test_ldb_add_key_len_eq_max,
557 ldbtest_setup,
558 ldbtest_teardown),
559 cmocka_unit_test_setup_teardown(
560 test_ldb_add_key_len_gt_max,
561 ldbtest_setup,
562 ldbtest_teardown),
563 cmocka_unit_test_setup_teardown(
564 test_ldb_add_key_len_2x_gt_max,
565 ldbtest_setup,
566 ldbtest_teardown),
567 cmocka_unit_test_setup_teardown(
568 test_ldb_add_special_key_len_eq_max,
569 ldbtest_setup_noguid,
570 ldbtest_teardown),
571 cmocka_unit_test_setup_teardown(
572 test_ldb_add_special_key_len_gt_max,
573 ldbtest_setup_noguid,
574 ldbtest_teardown),
575 cmocka_unit_test_setup_teardown(
576 test_ldb_add_dn_no_guid_mode,
577 ldbtest_setup_noguid,
578 ldbtest_teardown),
579 cmocka_unit_test_setup_teardown(
580 test_multiple_opens,
581 ldbtest_setup,
582 ldbtest_teardown),
583 cmocka_unit_test_setup_teardown(
584 test_multiple_opens_across_fork,
585 ldbtest_setup,
586 ldbtest_teardown),
587 };
588
589 return cmocka_run_group_tests(tests, NULL, NULL);
590 }
591