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