1/*-
2 * Copyright (c) 2021 Mariusz Zaborski <oshogbo@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
14 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
15 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23 * POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD$");
28
29#include <sys/param.h>
30#include <sys/capsicum.h>
31#include <sys/stat.h>
32
33#include <errno.h>
34#include <fcntl.h>
35#include <stdio.h>
36
37#include <atf-c.h>
38
39#include <libcasper.h>
40#include <casper/cap_fileargs.h>
41
42#define MAX_FILES		200
43
44static char *files[MAX_FILES];
45static int fds[MAX_FILES];
46
47#define	TEST_FILE	"/etc/passwd"
48
49static void
50prepare_files(size_t num, bool create)
51{
52	const char template[] = "testsfiles.XXXXXXXX";
53	size_t i;
54
55	for (i = 0; i < num; i++) {
56		files[i] = calloc(1, sizeof(template));
57		ATF_REQUIRE(files[i] != NULL);
58		strncpy(files[i], template, sizeof(template) - 1);
59
60		if (create) {
61			fds[i] = mkstemp(files[i]);
62			ATF_REQUIRE(fds[i] >= 0);
63		} else {
64			fds[i] = -1;
65			ATF_REQUIRE(mktemp(files[i]) != NULL);
66		}
67	}
68}
69
70static void
71clear_files(void)
72{
73	size_t i;
74
75
76	for (i = 0; files[i] != NULL; i++) {
77		unlink(files[i]);
78		free(files[i]);
79		if (fds[i] != -1)
80			close(fds[i]);
81	}
82}
83
84static int
85test_file_open(fileargs_t *fa, const char *file, int *fdp)
86{
87	int fd;
88
89	fd = fileargs_open(fa, file);
90	if (fd < 0)
91		return (errno);
92
93	if (fdp != NULL) {
94		*fdp = fd;
95	}
96
97	return (0);
98}
99
100static int
101test_file_fopen(fileargs_t *fa, const char *file, const char *mode,
102    FILE **retfile)
103{
104	FILE *pfile;
105
106	pfile = fileargs_fopen(fa, file, mode);
107	if (pfile == NULL)
108		return (errno);
109
110	if (retfile != NULL) {
111		*retfile = pfile;
112	}
113
114	return (0);
115}
116
117static int
118test_file_lstat(fileargs_t *fa, const char *file)
119{
120	struct stat fasb, origsb;
121	bool equals;
122
123	if (fileargs_lstat(fa, file, &fasb) < 0)
124		return (errno);
125
126	ATF_REQUIRE(lstat(file, &origsb) == 0);
127
128	equals = true;
129	equals &= (origsb.st_dev == fasb.st_dev);
130	equals &= (origsb.st_ino == fasb.st_ino);
131	equals &= (origsb.st_nlink == fasb.st_nlink);
132	equals &= (origsb.st_flags == fasb.st_flags);
133	equals &= (memcmp(&origsb.st_ctim, &fasb.st_ctim,
134	    sizeof(fasb.st_ctim)) == 0);
135	equals &= (memcmp(&origsb.st_birthtim, &fasb.st_birthtim,
136	    sizeof(fasb.st_birthtim)) == 0);
137	if (!equals) {
138		return (EINVAL);
139	}
140
141	return (0);
142}
143
144static int
145test_file_realpath_static(fileargs_t *fa, const char *file)
146{
147	char fapath[PATH_MAX], origpath[PATH_MAX];
148
149	if (fileargs_realpath(fa, file, fapath) == NULL)
150		return (errno);
151
152	ATF_REQUIRE(realpath(file, origpath) != NULL);
153
154	if (strcmp(fapath, origpath) != 0)
155		return (EINVAL);
156
157	return (0);
158}
159
160static int
161test_file_realpath_alloc(fileargs_t *fa, const char *file)
162{
163	char *fapath, *origpath;
164	int serrno;
165
166	fapath = fileargs_realpath(fa, file, NULL);
167	if (fapath == NULL)
168		return (errno);
169
170	origpath = realpath(file, NULL);
171	ATF_REQUIRE(origpath != NULL);
172
173	serrno = 0;
174	if (strcmp(fapath, origpath) != 0)
175		serrno = EINVAL;
176
177	free(fapath);
178	free(origpath);
179
180	return (serrno);
181}
182
183static int
184test_file_realpath(fileargs_t *fa, const char *file)
185{
186	int serrno;
187
188	serrno = test_file_realpath_static(fa, file);
189	if (serrno != 0)
190		return serrno;
191
192	return (test_file_realpath_alloc(fa, file));
193}
194
195static int
196test_file_mode(int fd, int mode)
197{
198	int flags;
199
200	flags = fcntl(fd, F_GETFL, 0);
201	if (flags < 0)
202		return (errno);
203
204	if ((flags & O_ACCMODE) != mode)
205		return (errno);
206
207	return (0);
208}
209
210static bool
211test_file_cap(int fd, cap_rights_t *rights)
212{
213	cap_rights_t fdrights;
214
215	ATF_REQUIRE(cap_rights_get(fd, &fdrights) == 0);
216
217	return (cap_rights_contains(&fdrights, rights));
218}
219
220static int
221test_file_write(int fd)
222{
223	char buf;
224
225	buf = 't';
226	if (write(fd, &buf, sizeof(buf)) != sizeof(buf)) {
227		return (errno);
228	}
229
230	return (0);
231}
232
233static int
234test_file_read(int fd)
235{
236	char buf;
237
238	if (read(fd, &buf, sizeof(buf)) < 0) {
239		return (errno);
240	}
241
242	return (0);
243}
244
245static int
246test_file_fwrite(FILE *pfile)
247{
248	char buf;
249
250	buf = 't';
251	if (fwrite(&buf, sizeof(buf), 1, pfile) != sizeof(buf))
252		return (errno);
253
254	return (0);
255}
256
257static int
258test_file_fread(FILE *pfile)
259{
260	char buf;
261	int ret, serrno;
262
263	errno = 0;
264	ret = fread(&buf, sizeof(buf), 1, pfile);
265	serrno = errno;
266	if (ret < 0) {
267		return (serrno);
268	} else if (ret == 0 && feof(pfile) == 0) {
269		return (serrno != 0 ? serrno : EINVAL);
270	}
271
272	return (0);
273}
274
275ATF_TC_WITH_CLEANUP(fileargs__open_read);
276ATF_TC_HEAD(fileargs__open_read, tc) {}
277ATF_TC_BODY(fileargs__open_read, tc)
278{
279	cap_rights_t rights, norights;
280	fileargs_t *fa;
281	size_t i;
282	int fd;
283
284	prepare_files(MAX_FILES, true);
285
286	cap_rights_init(&rights, CAP_READ | CAP_FCNTL);
287	cap_rights_init(&norights, CAP_WRITE);
288	fa = fileargs_init(MAX_FILES, files, O_RDONLY, 0, &rights,
289	    FA_OPEN);
290	ATF_REQUIRE(fa != NULL);
291
292	for (i = 0; i < MAX_FILES; i++) {
293		/* ALLOWED */
294		/* We open file twice to check if we can. */
295		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
296		ATF_REQUIRE(close(fd) == 0);
297
298		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
299		ATF_REQUIRE(test_file_mode(fd, O_RDONLY) == 0);
300		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
301		ATF_REQUIRE(test_file_read(fd) == 0);
302
303		/* DISALLOWED */
304		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
305		ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
306		ATF_REQUIRE(test_file_cap(fd, &norights) == false);
307		ATF_REQUIRE(test_file_write(fd) == ENOTCAPABLE);
308		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
309		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
310
311		/* CLOSE */
312		ATF_REQUIRE(close(fd) == 0);
313	}
314}
315ATF_TC_CLEANUP(fileargs__open_read, tc)
316{
317	clear_files();
318}
319
320ATF_TC_WITH_CLEANUP(fileargs__open_write);
321ATF_TC_HEAD(fileargs__open_write, tc) {}
322ATF_TC_BODY(fileargs__open_write, tc)
323{
324	cap_rights_t rights, norights;
325	fileargs_t *fa;
326	size_t i;
327	int fd;
328
329	prepare_files(MAX_FILES, true);
330
331	cap_rights_init(&rights, CAP_WRITE | CAP_FCNTL);
332	cap_rights_init(&norights, CAP_READ);
333	fa = fileargs_init(MAX_FILES, files, O_WRONLY, 0, &rights,
334	    FA_OPEN);
335	ATF_REQUIRE(fa != NULL);
336
337	for (i = 0; i < MAX_FILES; i++) {
338		/* ALLOWED */
339		/* We open file twice to check if we can. */
340		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
341		ATF_REQUIRE(close(fd) == 0);
342
343		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
344		ATF_REQUIRE(test_file_mode(fd, O_WRONLY) == 0);
345		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
346		ATF_REQUIRE(test_file_write(fd) == 0);
347
348		/* DISALLOWED */
349		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
350		ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
351		ATF_REQUIRE(test_file_cap(fd, &norights) == false);
352		ATF_REQUIRE(test_file_read(fd) == ENOTCAPABLE);
353		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
354		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
355
356		/* CLOSE */
357		ATF_REQUIRE(close(fd) == 0);
358	}
359}
360ATF_TC_CLEANUP(fileargs__open_write, tc)
361{
362	clear_files();
363}
364
365ATF_TC_WITH_CLEANUP(fileargs__open_create);
366ATF_TC_HEAD(fileargs__open_create, tc) {}
367ATF_TC_BODY(fileargs__open_create, tc)
368{
369	cap_rights_t rights, norights;
370	fileargs_t *fa;
371	size_t i;
372	int fd;
373
374	prepare_files(MAX_FILES, false);
375
376	cap_rights_init(&rights, CAP_WRITE | CAP_FCNTL | CAP_READ);
377	cap_rights_init(&norights, CAP_FCHMOD);
378	fa = fileargs_init(MAX_FILES, files, O_RDWR | O_CREAT, 666,
379	    &rights, FA_OPEN);
380	ATF_REQUIRE(fa != NULL);
381
382	for (i = 0; i < MAX_FILES; i++) {
383		/* ALLOWED */
384		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
385
386		ATF_REQUIRE(test_file_mode(fd, O_RDWR) == 0);
387		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
388		ATF_REQUIRE(test_file_write(fd) == 0);
389		ATF_REQUIRE(test_file_read(fd) == 0);
390
391		/* DISALLOWED */
392		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
393		ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
394		ATF_REQUIRE(test_file_cap(fd, &norights) == false);
395		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
396		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
397
398		/* CLOSE */
399		ATF_REQUIRE(close(fd) == 0);
400	}
401}
402ATF_TC_CLEANUP(fileargs__open_create, tc)
403{
404	clear_files();
405}
406
407ATF_TC_WITH_CLEANUP(fileargs__open_with_casper);
408ATF_TC_HEAD(fileargs__open_with_casper, tc) {}
409ATF_TC_BODY(fileargs__open_with_casper, tc)
410{
411	cap_channel_t *capcas;
412	cap_rights_t rights;
413	fileargs_t *fa;
414	size_t i;
415	int fd;
416
417	prepare_files(MAX_FILES, true);
418
419	capcas = cap_init();
420	ATF_REQUIRE(capcas != NULL);
421
422	cap_rights_init(&rights, CAP_READ);
423	fa = fileargs_cinit(capcas, MAX_FILES, files, O_RDONLY, 0, &rights,
424	    FA_OPEN);
425	ATF_REQUIRE(fa != NULL);
426
427	for (i = 0; i < MAX_FILES; i++) {
428		/* ALLOWED */
429		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
430		ATF_REQUIRE(test_file_read(fd) == 0);
431
432		/* CLOSE */
433		ATF_REQUIRE(close(fd) == 0);
434	}
435}
436ATF_TC_CLEANUP(fileargs__open_with_casper, tc)
437{
438	clear_files();
439}
440
441ATF_TC_WITH_CLEANUP(fileargs__fopen_read);
442ATF_TC_HEAD(fileargs__fopen_read, tc) {}
443ATF_TC_BODY(fileargs__fopen_read, tc)
444{
445	cap_rights_t rights, norights;
446	fileargs_t *fa;
447	size_t i;
448	FILE *pfile;
449	int fd;
450
451	prepare_files(MAX_FILES, true);
452
453	cap_rights_init(&rights, CAP_READ | CAP_FCNTL);
454	cap_rights_init(&norights, CAP_WRITE);
455	fa = fileargs_init(MAX_FILES, files, O_RDONLY, 0, &rights,
456	    FA_OPEN);
457	ATF_REQUIRE(fa != NULL);
458
459	for (i = 0; i < MAX_FILES; i++) {
460		/* ALLOWED */
461		/* We fopen file twice to check if we can. */
462		ATF_REQUIRE(test_file_fopen(fa, files[i], "r", &pfile) == 0);
463		ATF_REQUIRE(fclose(pfile) == 0);
464
465		ATF_REQUIRE(test_file_fopen(fa, files[i], "r", &pfile) == 0);
466		fd = fileno(pfile);
467		ATF_REQUIRE(test_file_mode(fd, O_RDONLY) == 0);
468		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
469		ATF_REQUIRE(test_file_fread(pfile) == 0);
470
471		/* DISALLOWED */
472		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
473		ATF_REQUIRE(test_file_fopen(fa, TEST_FILE, "r", NULL) ==
474		    ENOTCAPABLE);
475		ATF_REQUIRE(test_file_cap(fd, &norights) == false);
476		ATF_REQUIRE(test_file_fwrite(pfile) == EBADF);
477		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
478		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
479
480		/* CLOSE */
481		ATF_REQUIRE(fclose(pfile) == 0);
482	}
483}
484ATF_TC_CLEANUP(fileargs__fopen_read, tc)
485{
486	clear_files();
487}
488
489ATF_TC_WITH_CLEANUP(fileargs__fopen_write);
490ATF_TC_HEAD(fileargs__fopen_write, tc) {}
491ATF_TC_BODY(fileargs__fopen_write, tc)
492{
493	cap_rights_t rights, norights;
494	fileargs_t *fa;
495	size_t i;
496	FILE *pfile;
497	int fd;
498
499	prepare_files(MAX_FILES, true);
500
501	cap_rights_init(&rights, CAP_WRITE | CAP_FCNTL);
502	cap_rights_init(&norights, CAP_READ);
503	fa = fileargs_init(MAX_FILES, files, O_WRONLY, 0, &rights,
504	    FA_OPEN);
505	ATF_REQUIRE(fa != NULL);
506
507	for (i = 0; i < MAX_FILES; i++) {
508		/* ALLOWED */
509		/* We fopen file twice to check if we can. */
510		ATF_REQUIRE(test_file_fopen(fa, files[i], "w", &pfile) == 0);
511		ATF_REQUIRE(fclose(pfile) == 0);
512
513		ATF_REQUIRE(test_file_fopen(fa, files[i], "w", &pfile) == 0);
514		fd = fileno(pfile);
515		ATF_REQUIRE(test_file_mode(fd, O_WRONLY) == 0);
516		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
517		ATF_REQUIRE(test_file_fwrite(pfile) == 0);
518
519		/* DISALLOWED */
520		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
521		ATF_REQUIRE(test_file_fopen(fa, TEST_FILE, "w", NULL) ==
522		    ENOTCAPABLE);
523		ATF_REQUIRE(test_file_cap(fd, &norights) == false);
524		ATF_REQUIRE(test_file_fread(pfile) == EBADF);
525		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
526		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
527
528		/* CLOSE */
529		ATF_REQUIRE(fclose(pfile) == 0);
530	}
531}
532ATF_TC_CLEANUP(fileargs__fopen_write, tc)
533{
534	clear_files();
535}
536
537ATF_TC_WITH_CLEANUP(fileargs__fopen_create);
538ATF_TC_HEAD(fileargs__fopen_create, tc) {}
539ATF_TC_BODY(fileargs__fopen_create, tc)
540{
541	cap_rights_t rights;
542	fileargs_t *fa;
543	size_t i;
544	FILE *pfile;
545	int fd;
546
547	prepare_files(MAX_FILES, false);
548
549	cap_rights_init(&rights, CAP_READ | CAP_WRITE | CAP_FCNTL);
550	fa = fileargs_init(MAX_FILES, files, O_RDWR | O_CREAT, 0, &rights,
551	    FA_OPEN);
552	ATF_REQUIRE(fa != NULL);
553
554	for (i = 0; i < MAX_FILES; i++) {
555		/* ALLOWED */
556		/* We fopen file twice to check if we can. */
557		ATF_REQUIRE(test_file_fopen(fa, files[i], "w+", &pfile) == 0);
558		fd = fileno(pfile);
559		ATF_REQUIRE(test_file_mode(fd, O_RDWR) == 0);
560		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
561		ATF_REQUIRE(test_file_fwrite(pfile) == 0);
562		ATF_REQUIRE(test_file_fread(pfile) == 0);
563
564		/* DISALLOWED */
565		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
566		ATF_REQUIRE(test_file_fopen(fa, TEST_FILE, "w+", NULL) ==
567		    ENOTCAPABLE);
568		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
569		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
570
571		/* CLOSE */
572		ATF_REQUIRE(fclose(pfile) == 0);
573	}
574}
575ATF_TC_CLEANUP(fileargs__fopen_create, tc)
576{
577	clear_files();
578}
579
580ATF_TC_WITH_CLEANUP(fileargs__lstat);
581ATF_TC_HEAD(fileargs__lstat, tc) {}
582ATF_TC_BODY(fileargs__lstat, tc)
583{
584	fileargs_t *fa;
585	size_t i;
586	int fd;
587
588	prepare_files(MAX_FILES, true);
589
590	fa = fileargs_init(MAX_FILES, files, 0, 0, NULL, FA_LSTAT);
591	ATF_REQUIRE(fa != NULL);
592
593	for (i = 0; i < MAX_FILES; i++) {
594		/* ALLOWED */
595		ATF_REQUIRE(test_file_lstat(fa, files[i]) == 0);
596
597		/* DISALLOWED */
598		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == ENOTCAPABLE);
599		ATF_REQUIRE(test_file_lstat(fa, TEST_FILE) == ENOTCAPABLE);
600		ATF_REQUIRE(test_file_open(fa, TEST_FILE, &fd) == ENOTCAPABLE);
601		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
602		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
603	}
604}
605ATF_TC_CLEANUP(fileargs__lstat, tc)
606{
607	clear_files();
608}
609
610ATF_TC_WITH_CLEANUP(fileargs__realpath);
611ATF_TC_HEAD(fileargs__realpath, tc) {}
612ATF_TC_BODY(fileargs__realpath, tc)
613{
614	fileargs_t *fa;
615	size_t i;
616	int fd;
617
618	prepare_files(MAX_FILES, true);
619
620	fa = fileargs_init(MAX_FILES, files, 0, 0, NULL, FA_REALPATH);
621	ATF_REQUIRE(fa != NULL);
622
623	for (i = 0; i < MAX_FILES; i++) {
624		/* ALLOWED */
625		ATF_REQUIRE(test_file_realpath(fa, files[i]) == 0);
626
627		/* DISALLOWED */
628		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == ENOTCAPABLE);
629		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
630		ATF_REQUIRE(test_file_lstat(fa, TEST_FILE) == ENOTCAPABLE);
631		ATF_REQUIRE(test_file_open(fa, TEST_FILE, &fd) == ENOTCAPABLE);
632		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
633	}
634}
635ATF_TC_CLEANUP(fileargs__realpath, tc)
636{
637	clear_files();
638}
639
640ATF_TC_WITH_CLEANUP(fileargs__open_lstat);
641ATF_TC_HEAD(fileargs__open_lstat, tc) {}
642ATF_TC_BODY(fileargs__open_lstat, tc)
643{
644	cap_rights_t rights, norights;
645	fileargs_t *fa;
646	size_t i;
647	int fd;
648
649	prepare_files(MAX_FILES, true);
650
651	cap_rights_init(&rights, CAP_READ | CAP_FCNTL);
652	cap_rights_init(&norights, CAP_WRITE);
653	fa = fileargs_init(MAX_FILES, files, O_RDONLY, 0, &rights,
654	    FA_OPEN | FA_LSTAT);
655	ATF_REQUIRE(fa != NULL);
656
657	for (i = 0; i < MAX_FILES; i++) {
658		/* ALLOWED */
659		/* We open file twice to check if we can. */
660		ATF_REQUIRE(test_file_lstat(fa, files[i]) == 0);
661		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
662		ATF_REQUIRE(close(fd) == 0);
663
664		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
665		ATF_REQUIRE(test_file_lstat(fa, files[i]) == 0);
666		ATF_REQUIRE(test_file_mode(fd, O_RDONLY) == 0);
667		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
668		ATF_REQUIRE(test_file_read(fd) == 0);
669
670		/* DISALLOWED */
671		ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
672		ATF_REQUIRE(test_file_cap(fd, &norights) == false);
673		ATF_REQUIRE(test_file_write(fd) == ENOTCAPABLE);
674		ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
675		ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
676
677		/* CLOSE */
678		ATF_REQUIRE(close(fd) == 0);
679	}
680}
681ATF_TC_CLEANUP(fileargs__open_lstat, tc)
682{
683	clear_files();
684}
685
686ATF_TC_WITH_CLEANUP(fileargs__open_realpath);
687ATF_TC_HEAD(fileargs__open_realpath, tc) {}
688ATF_TC_BODY(fileargs__open_realpath, tc)
689{
690	cap_rights_t rights, norights;
691	fileargs_t *fa;
692	size_t i;
693	int fd;
694
695	prepare_files(MAX_FILES, true);
696
697	cap_rights_init(&rights, CAP_READ | CAP_FCNTL);
698	cap_rights_init(&norights, CAP_WRITE);
699	fa = fileargs_init(MAX_FILES, files, O_RDONLY, 0, &rights,
700	    FA_OPEN | FA_REALPATH);
701	ATF_REQUIRE(fa != NULL);
702
703	for (i = 0; i < MAX_FILES; i++) {
704		/* ALLOWED */
705		/* We open file twice to check if we can. */
706		ATF_REQUIRE(test_file_realpath(fa, files[i]) == 0);
707		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
708		ATF_REQUIRE(close(fd) == 0);
709
710		ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
711		ATF_REQUIRE(test_file_realpath(fa, files[i]) == 0);
712		ATF_REQUIRE(test_file_mode(fd, O_RDONLY) == 0);
713		ATF_REQUIRE(test_file_cap(fd, &rights) == true);
714		ATF_REQUIRE(test_file_read(fd) == 0);
715
716		/* DISALLOWED */
717		ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
718		ATF_REQUIRE(test_file_cap(fd, &norights) == false);
719		ATF_REQUIRE(test_file_write(fd) == ENOTCAPABLE);
720		ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
721
722		/* CLOSE */
723		ATF_REQUIRE(close(fd) == 0);
724	}
725}
726ATF_TC_CLEANUP(fileargs__open_realpath, tc)
727{
728	clear_files();
729}
730
731ATF_TP_ADD_TCS(tp)
732{
733
734	ATF_TP_ADD_TC(tp, fileargs__open_create);
735	ATF_TP_ADD_TC(tp, fileargs__open_read);
736	ATF_TP_ADD_TC(tp, fileargs__open_write);
737	ATF_TP_ADD_TC(tp, fileargs__open_with_casper);
738
739	ATF_TP_ADD_TC(tp, fileargs__fopen_create);
740	ATF_TP_ADD_TC(tp, fileargs__fopen_read);
741	ATF_TP_ADD_TC(tp, fileargs__fopen_write);
742
743	ATF_TP_ADD_TC(tp, fileargs__lstat);
744
745	ATF_TP_ADD_TC(tp, fileargs__realpath);
746
747	ATF_TP_ADD_TC(tp, fileargs__open_lstat);
748	ATF_TP_ADD_TC(tp, fileargs__open_realpath);
749
750	return (atf_no_error());
751}
752