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