1221431Sjonathan/*-
2221431Sjonathan * Copyright (c) 2008-2011 Robert N. M. Watson
3224651Sjonathan * Copyright (c) 2011 Jonathan Anderson
4221431Sjonathan * All rights reserved.
5221431Sjonathan *
6221431Sjonathan * Redistribution and use in source and binary forms, with or without
7221431Sjonathan * modification, are permitted provided that the following conditions
8221431Sjonathan * are met:
9221431Sjonathan * 1. Redistributions of source code must retain the above copyright
10221431Sjonathan *    notice, this list of conditions and the following disclaimer.
11221431Sjonathan * 2. Redistributions in binary form must reproduce the above copyright
12221431Sjonathan *    notice, this list of conditions and the following disclaimer in the
13221431Sjonathan *    documentation and/or other materials provided with the distribution.
14221431Sjonathan *
15221431Sjonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16221431Sjonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17221431Sjonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18221431Sjonathan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19221431Sjonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20221431Sjonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21221431Sjonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22221431Sjonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23221431Sjonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24221431Sjonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25221431Sjonathan * SUCH DAMAGE.
26221431Sjonathan *
27221431Sjonathan * $FreeBSD$
28221431Sjonathan */
29221431Sjonathan
30221431Sjonathan#ifndef CAP_TEST_H
31221431Sjonathan#define	CAP_TEST_H
32221431Sjonathan
33224651Sjonathan#include <err.h>
34221431Sjonathan
35224651Sjonathan/*
36224651Sjonathan * Define a file required by a test. The test can't complete without the file,
37224651Sjonathan * so if we don't have it, just die.
38224651Sjonathan */
39224651Sjonathan#define	REQUIRE(fd)	do {						\
40224651Sjonathan	if ((fd) < 0)							\
41224651Sjonathan		err(-1, "%s:%d: Missing required file '%s'",		\
42224651Sjonathan			__FILE__, __LINE__, #fd);			\
43224651Sjonathan} while (0)
44224651Sjonathan
45224651Sjonathan/* Whether a test passed or failed. */
46224651Sjonathan#define	PASSED	0
47224651Sjonathan#define	FAILED	1
48224651Sjonathan
49224651Sjonathan/* A test has failed; print a message and clear the 'success' flag. */
50224651Sjonathan#define	FAIL(...)	do {						\
51224651Sjonathan	warn(__VA_ARGS__);						\
52224651Sjonathan	success = FAILED;						\
53224651Sjonathan} while (0)
54224651Sjonathan
55224651Sjonathan/* As above, but do not print the errno message. */
56224651Sjonathan#define	FAILX(...)	do {						\
57224651Sjonathan	warnx(__VA_ARGS__);						\
58224651Sjonathan	success = FAILED;						\
59224651Sjonathan} while (0)
60224651Sjonathan
61224651Sjonathan/* Like an assertion, but don't kill the test, just fail and keep going. */
62224651Sjonathan#define	CHECK(condition) do {						\
63224651Sjonathan	if (!(condition))						\
64224651Sjonathan		FAILX("%s:%d: Assertion '%s' failed",			\
65224651Sjonathan		    __func__, __LINE__, #condition);			\
66224651Sjonathan} while (0)
67224651Sjonathan
68224651Sjonathan/* Make sure that a system call's return value is >= 0. */
69224651Sjonathan#define	CHECK_SYSCALL_SUCCEEDS(syscall, ...) do {			\
70224651Sjonathan	if (syscall(__VA_ARGS__) < 0)					\
71224651Sjonathan		FAIL("%s() at line %d: %s failed",			\
72224651Sjonathan		    __func__, __LINE__, #syscall);			\
73224651Sjonathan} while (0)
74224651Sjonathan
75224651Sjonathan/* Make sure that a system call fails with the correct errno. */
76224651Sjonathan#define	CHECK_SYSCALL_FAILS(expected_errno, syscall, ...)	do {	\
77224651Sjonathan	if (syscall(__VA_ARGS__) < 0) {					\
78224651Sjonathan		if (errno != expected_errno)				\
79224651Sjonathan			FAIL("%s() at line %d: %s",			\
80224651Sjonathan			    __func__, __LINE__, #syscall);		\
81224651Sjonathan	} else {							\
82224651Sjonathan		FAILX("%s() at line %d: %s succeeded; it should've failed", \
83224651Sjonathan		    __func__, __LINE__, #syscall);			\
84224651Sjonathan	}								\
85224651Sjonathan} while (0)
86224651Sjonathan
87224651Sjonathan/* Make sure that a system call fails, but not with a particular errno. */
88224651Sjonathan#define	CHECK_SYSCALL_FAILS_BUT_NOT_WITH(bad_errno, syscall, ...)	do { \
89224651Sjonathan	if (syscall(__VA_ARGS__) < 0) {					\
90224651Sjonathan		if (errno == bad_errno)					\
91224651Sjonathan			FAIL("%s() at line %d: %s",			\
92224651Sjonathan			    __func__, __LINE__, #syscall);		\
93224651Sjonathan	} else {							\
94224651Sjonathan		FAILX("%s() at line %d: %s succeeded; it should've failed", \
95224651Sjonathan		    __func__, __LINE__, #syscall);			\
96224651Sjonathan	}								\
97224651Sjonathan} while (0)
98224651Sjonathan
99224651Sjonathan/* A system call should fail with ECAPMODE. */
100224651Sjonathan#define	CHECK_CAPMODE(...) \
101224651Sjonathan	CHECK_SYSCALL_FAILS(ECAPMODE, __VA_ARGS__)
102224651Sjonathan
103224651Sjonathan/* A system call should fail, but not with ECAPMODE. */
104224651Sjonathan#define	CHECK_NOT_CAPMODE(...) \
105224651Sjonathan	CHECK_SYSCALL_FAILS_BUT_NOT_WITH(ECAPMODE, __VA_ARGS__)
106224651Sjonathan
107224651Sjonathan/* A system call should fail with ENOTCAPABLE. */
108224651Sjonathan#define	CHECK_NOTCAPABLE(...) \
109224651Sjonathan	CHECK_SYSCALL_FAILS(ENOTCAPABLE, __VA_ARGS__)
110224651Sjonathan
111224651Sjonathan/* Ensure that 'rights' are a subset of 'max'. */
112224651Sjonathan#define	CHECK_RIGHTS(rights, max)	do {				\
113224651Sjonathan	if ((success == PASSED) && (rights != max))			\
114224651Sjonathan		FAILX("Rights of opened file (%jx) > maximum (%jx)",	\
115224651Sjonathan		    (cap_rights_t) rights, (cap_rights_t) max);		\
116224651Sjonathan} while (0)
117224651Sjonathan
118224651Sjonathan/* Create a capability from a file descriptor, make sure it succeeds. */
119224651Sjonathan#define	MAKE_CAPABILITY(to, from, rights)	do {			\
120224651Sjonathan	cap_rights_t _rights;						\
121224651Sjonathan	REQUIRE(to = cap_new(from, rights));				\
122224651Sjonathan	CHECK_SYSCALL_SUCCEEDS(cap_getrights, to, &_rights);		\
123224651Sjonathan	if ((success == PASSED) && (_rights != (rights)))		\
124224651Sjonathan		FAILX("New capability's rights (%jx) != %jx",		\
125224651Sjonathan		    _rights, (cap_rights_t) (rights));			\
126224651Sjonathan} while (0)
127224651Sjonathan
128224651Sjonathan/*
129224651Sjonathan * A top-level test should take no arguments and return an integer value,
130224651Sjonathan * either PASSED or FAILED.
131224651Sjonathan *
132224651Sjonathan * Errors such as SIGSEGV will be caught and interpreted as FAILED.
133224651Sjonathan */
134224651Sjonathantypedef int	(*test_function)(void);
135224651Sjonathan
136224651Sjonathan/* Information about a test. */
137224651Sjonathanstruct test {
138224651Sjonathan	char		*t_name;
139224651Sjonathan	test_function	 t_run;
140224651Sjonathan	int		 t_result;
141224651Sjonathan};
142224651Sjonathan
143224651Sjonathan/*
144224651Sjonathan * Run a test in a child process so that cap_enter(2) doesn't mess up
145224651Sjonathan * subsequent tests.
146224651Sjonathan */
147224651Sjonathanint	execute(int id, struct test*);
148224651Sjonathan
149224651Sjonathanint	test_capmode(void);
150224651Sjonathanint	test_capabilities(void);
151224793Sjonathanint	test_fcntl(void);
152224989Sjonathanint	test_pdfork(void);
153224989Sjonathanint	test_pdkill(void);
154224989Sjonathanint	test_pdwait(void);
155224793Sjonathanint	test_relative(void);
156224651Sjonathanint	test_sysctl(void);
157224651Sjonathan
158221431Sjonathan#endif /* CAP_TEST_H */
159