1/* Authors: Christopher Ashworth <cashworth@tresys.com>
2 *          Caleb Case <ccase@tresys.com>
3 *          Chris PeBenito <cpebenito@tresys.com>
4 *
5 * Copyright (C) 2006 Tresys Technology, LLC
6 *
7 *  This library is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU Lesser General Public
9 *  License as published by the Free Software Foundation; either
10 *  version 2.1 of the License, or (at your option) any later version.
11 *
12 *  This library is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 *  Lesser General Public License for more details.
16 *
17 *  You should have received a copy of the GNU Lesser General Public
18 *  License along with this library; if not, write to the Free Software
19 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22/*  The purpose of this file is to provide unit tests of the functions in:
23 *
24 *  libsemanage/src/semanage_store.c
25 *
26 */
27
28#include "handle.h"
29#include "semanage_store.h"
30
31#include "utilities.h"
32#include "test_semanage_store.h"
33
34#include <libgen.h>
35#include <limits.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <sys/mman.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <fcntl.h>
43#include <unistd.h>
44#include <CUnit/Basic.h>
45
46semanage_handle_t *sh = NULL;
47const char *rootpath = "./test-policy";
48const char *polpath = "./test-policy/store/";
49const char *readlockpath = "./test-policy/store/semanage.read.LOCK";
50const char *translockpath = "./test-policy/store/semanage.trans.LOCK";
51const char *actpath = "./test-policy/store/active";
52const char *modpath = "./test-policy/store/active/modules";
53
54/* The suite initialization function.
55 * Returns zero on success, non-zero otherwise.
56 */
57int semanage_store_test_init(void)
58{
59	int err;
60
61	/* create directories */
62	err = mkdir(rootpath, S_IRUSR | S_IWUSR | S_IXUSR);
63	if (err != 0)
64		return -1;
65
66	err = mkdir(polpath, S_IRUSR | S_IWUSR | S_IXUSR);
67	if (err != 0)
68		return -1;
69
70	err = mkdir(actpath, S_IRUSR | S_IWUSR | S_IXUSR);
71	if (err != 0)
72		return -1;
73
74	err = mkdir(modpath, S_IRUSR | S_IWUSR | S_IXUSR);
75	if (err != 0)
76		return -1;
77
78	/* initialize the handle */
79	sh = semanage_handle_create();
80	if (sh == NULL)
81		return -1;
82
83	/* hide error messages */
84	sh->msg_callback = test_msg_handler;
85
86	/* use our own policy store */
87	free(sh->conf->store_path);
88	sh->conf->store_path = strdup("store");
89
90	/* initialize paths */
91	err = semanage_check_init(sh, rootpath);
92	if (err != 0)
93		return -1;
94
95	return 0;
96}
97
98/* The suite cleanup function.
99 * Returns zero on success, non-zero otherwise.
100 */
101int semanage_store_test_cleanup(void)
102{
103	int err;
104
105	/* remove the test policy directories */
106	err = rmdir(modpath);
107	if (err != 0)
108		return -1;
109
110	err = rmdir(actpath);
111	if (err != 0)
112		return -1;
113
114	err = rmdir(polpath);
115	if (err != 0)
116		return -1;
117
118	err = rmdir(rootpath);
119	if (err != 0)
120		return -1;
121
122	/* cleanup the handle */
123	semanage_handle_destroy(sh);
124	return 0;
125}
126
127/* Adds all the tests needed for this suite.
128 */
129int semanage_store_add_tests(CU_pSuite suite)
130{
131	if (NULL ==
132	    CU_add_test(suite, "semanage_store_access_check",
133			test_semanage_store_access_check)) {
134		CU_cleanup_registry();
135		return CU_get_error();
136	}
137
138	if (NULL ==
139	    CU_add_test(suite, "semanage_get_lock", test_semanage_get_lock)) {
140		CU_cleanup_registry();
141		return CU_get_error();
142	}
143
144	if (NULL ==
145	    CU_add_test(suite, "semanage_nc_sort", test_semanage_nc_sort)) {
146		CU_cleanup_registry();
147		return CU_get_error();
148	}
149
150	return 0;
151}
152
153/* Tests the semanage_store_access_check function in semanage_store.c
154 */
155void test_semanage_store_access_check(void)
156{
157	int err;
158
159	/* create lock file */
160	err = mknod(readlockpath, S_IRUSR | S_IWUSR, S_IFREG);
161
162	/* check with permissions 000 */
163	err = chmod(modpath, 0);
164	CU_ASSERT(err == 0);
165	err = chmod(readlockpath, 0);
166	CU_ASSERT(err == 0);
167	err = chmod(polpath, 0);
168	CU_ASSERT(err == 0);
169
170	err = semanage_store_access_check();
171	CU_ASSERT(err == -1);
172
173	/* check with permissions 500 */
174	err = chmod(polpath, S_IRUSR | S_IXUSR);
175	CU_ASSERT(err == 0);
176	err = chmod(readlockpath, S_IRUSR);
177	CU_ASSERT(err == 0);
178	err = chmod(modpath, S_IRUSR | S_IXUSR);
179	CU_ASSERT(err == 0);
180
181	err = semanage_store_access_check();
182	CU_ASSERT(err == SEMANAGE_CAN_READ);
183
184	/* check with permissions 700 */
185	err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR);
186	CU_ASSERT(err == 0);
187	err = chmod(readlockpath, S_IRUSR | S_IWUSR);
188	CU_ASSERT(err == 0);
189	err = chmod(modpath, S_IRUSR | S_IWUSR | S_IXUSR);
190	CU_ASSERT(err == 0);
191
192	err = semanage_store_access_check();
193	CU_ASSERT(err == SEMANAGE_CAN_WRITE);
194
195	/* check with lock file 000 and others 500 */
196	err = chmod(polpath, S_IRUSR | S_IXUSR);
197	CU_ASSERT(err == 0);
198	err = chmod(readlockpath, 0);
199	CU_ASSERT(err == 0);
200	err = chmod(modpath, S_IRUSR | S_IXUSR);
201	CU_ASSERT(err == 0);
202
203	err = semanage_store_access_check();
204	CU_ASSERT(err == 0);
205
206	/* check with lock file 000 and others 700 */
207	err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR);
208	CU_ASSERT(err == 0);
209	err = chmod(readlockpath, 0);
210	CU_ASSERT(err == 0);
211	err = chmod(modpath, S_IRUSR | S_IWUSR | S_IXUSR);
212	CU_ASSERT(err == 0);
213
214	err = semanage_store_access_check();
215	CU_ASSERT(err == 0);
216
217	/* remove lock file */
218	err = remove(readlockpath);
219	CU_ASSERT(err == 0);
220
221	/* check with no lock file and 000 */
222	err = chmod(modpath, 0);
223	CU_ASSERT(err == 0);
224	err = chmod(polpath, 0);
225	CU_ASSERT(err == 0);
226
227	err = semanage_store_access_check();
228	CU_ASSERT(err == -1);
229
230	/* check with no lock file and 500 */
231	err = chmod(polpath, S_IRUSR | S_IXUSR);
232	CU_ASSERT(err == 0);
233	err = chmod(modpath, S_IRUSR | S_IXUSR);
234	CU_ASSERT(err == 0);
235
236	err = semanage_store_access_check();
237	CU_ASSERT(err == 0);
238
239	/* check with no lock file but write in polpath */
240	err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR);
241	CU_ASSERT(err == 0);
242
243	err = semanage_store_access_check();
244	CU_ASSERT(err == SEMANAGE_CAN_READ);
245
246	/* check with no lock file and 700 */
247	err = chmod(polpath, S_IRUSR | S_IWUSR | S_IXUSR);
248	CU_ASSERT(err == 0);
249	err = chmod(modpath, S_IRUSR | S_IWUSR | S_IXUSR);
250	CU_ASSERT(err == 0);
251
252	err = semanage_store_access_check();
253	CU_ASSERT(err == SEMANAGE_CAN_WRITE);
254}
255
256/* Tests the semanage_get_lock functions in semanage_store.c
257 */
258void test_semanage_get_lock(void)
259{
260	int err;
261
262	/* attempt to get an active lock */
263	err = semanage_get_active_lock(sh);
264	CU_ASSERT(err == 0);
265
266	/* attempt to get the lock again */
267	err = semanage_get_active_lock(sh);
268	CU_ASSERT(err == 0);
269
270	/* attempt to release the active lock */
271	semanage_release_active_lock(sh);
272
273	/* attempt to get an active lock */
274	err = semanage_get_active_lock(sh);
275	CU_ASSERT(err == 0);
276
277	/* attempt to release the active lock */
278	semanage_release_active_lock(sh);
279
280	/* attempt to get a trans lock */
281	err = semanage_get_trans_lock(sh);
282	CU_ASSERT(err == 0);
283
284	/* attempt to get the lock again */
285	err = semanage_get_trans_lock(sh);
286	CU_ASSERT(err == 0);
287
288	/* attempt to release the trans lock */
289	semanage_release_trans_lock(sh);
290
291	/* attempt to get a trans lock */
292	err = semanage_get_trans_lock(sh);
293	CU_ASSERT(err == 0);
294
295	/* attempt to release the trans lock */
296	semanage_release_trans_lock(sh);
297
298	/* remove the lock files */
299	err = remove(readlockpath);
300	CU_ASSERT(err == 0);
301	err = remove(translockpath);
302	CU_ASSERT(err == 0);
303}
304
305/* Tests the semanage_nc_sort function in semanage_store.c
306 */
307void test_semanage_nc_sort(void)
308{
309	char *source_buf, *sorted_buf = NULL, *good_buf, *bad_buf;
310	size_t source_buf_len, sorted_buf_len, good_buf_len, bad_buf_len;
311	int sourcefd, goodfd, badfd, err;
312	struct stat sb;
313
314	/* open source file */
315	sourcefd = open("nc_sort_unsorted", O_RDONLY);
316	if (sourcefd < 0) {
317		CU_FAIL("Missing nc_sort_unsorted test file.");
318		return;
319	}
320	fstat(sourcefd, &sb);
321	source_buf_len = sb.st_size;
322	source_buf =
323	    (char *)mmap(NULL, source_buf_len, PROT_READ, MAP_PRIVATE, sourcefd,
324			 0);
325
326	/* open good result file */
327	goodfd = open("nc_sort_sorted", O_RDONLY);
328	if (goodfd < 0) {
329		CU_FAIL("Missing nc_sort_sorted test file.");
330		goto out2;
331	}
332	fstat(goodfd, &sb);
333	good_buf_len = sb.st_size;
334	good_buf =
335	    (char *)mmap(NULL, good_buf_len, PROT_READ, MAP_PRIVATE, goodfd, 0);
336
337	/* open malformed source file (missing priorities) */
338	badfd = open("nc_sort_malformed", O_RDONLY);
339	if (badfd < 0) {
340		CU_FAIL("Missing nc_sort_malformed test file.");
341		goto out1;
342	}
343	fstat(badfd, &sb);
344	bad_buf_len = sb.st_size;
345	bad_buf =
346	    (char *)mmap(NULL, bad_buf_len, PROT_READ, MAP_PRIVATE, badfd, 0);
347
348	/* sort test file */
349	err =
350	    semanage_nc_sort(sh, source_buf, source_buf_len, &sorted_buf,
351			     &sorted_buf_len);
352	CU_ASSERT_FALSE(err);
353	CU_ASSERT_STRING_EQUAL(sorted_buf, good_buf);
354
355	/* reset for reuse in next test */
356	free(sorted_buf);
357	sorted_buf = NULL;
358
359	/* sort malformed source file */
360	err =
361	    semanage_nc_sort(sh, bad_buf, bad_buf_len, &sorted_buf,
362			     &sorted_buf_len);
363	CU_ASSERT_EQUAL(err, -1);
364
365	free(sorted_buf);
366
367	munmap(bad_buf, bad_buf_len);
368	close(badfd);
369      out1:
370	munmap(good_buf, good_buf_len);
371	close(goodfd);
372      out2:
373	munmap(source_buf, source_buf_len);
374	close(sourcefd);
375}
376