1/*-
2 * Copyright (c) 2007 Bjoern A. Zeeb
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
18 * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
20 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29/*
30 * Confirm that privilege is required to open a pfkey socket, and that this
31 * is not allowed in jail.
32 */
33
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <net/pfkeyv2.h>
37#include <netinet/in.h>
38#include <netipsec/ipsec.h>
39
40#include <err.h>
41#include <errno.h>
42#include <stdlib.h>
43#include <unistd.h>
44
45#include "main.h"
46
47static char	policy_bypass[]	= "in bypass";
48static char	policy_entrust[] = "in entrust";
49static char	*bypassbuf = NULL;
50static char	*entrustbuf = NULL;
51static int	sd = -1;
52
53
54static int
55priv_netinet_ipsec_policy_bypass_setup_af(int asroot, int injail,
56    struct test *test, int af)
57{
58
59	bypassbuf = ipsec_set_policy(policy_bypass, sizeof(policy_bypass) - 1);
60	if (bypassbuf == NULL) {
61		warn("%s: ipsec_set_policy(NULL)", __func__);
62		return (-1);
63	}
64	switch (af) {
65	case AF_INET:
66		sd = socket(AF_INET, SOCK_DGRAM, 0);
67		if (sd < 0) {
68			warn("%s: socket4", __func__);
69			return (-1);
70		}
71		break;
72#ifdef INET6
73	case AF_INET6:
74		sd = socket(AF_INET6, SOCK_DGRAM, 0);
75		if (sd < 0) {
76			warn("%s: socket6", __func__);
77			return (-1);
78		}
79		break;
80#endif
81	default:
82		warnx("%s: unexpected address family", __func__);
83		return (-1);
84	}
85	return (0);
86}
87
88int
89priv_netinet_ipsec_policy4_bypass_setup(int asroot, int injail,
90    struct test *test)
91{
92
93	return (priv_netinet_ipsec_policy_bypass_setup_af(asroot, injail, test,
94	    AF_INET));
95}
96
97#ifdef INET6
98int
99priv_netinet_ipsec_policy6_bypass_setup(int asroot, int injail,
100    struct test *test)
101{
102
103	return (priv_netinet_ipsec_policy_bypass_setup_af(asroot, injail, test,
104	    AF_INET6));
105}
106#endif
107
108
109static int
110priv_netinet_ipsec_policy_entrust_setup_af(int asroot, int injail,
111    struct test *test, int af)
112{
113
114	entrustbuf = ipsec_set_policy(policy_entrust, sizeof(policy_entrust)-1);
115	if (entrustbuf == NULL) {
116		warn("%s: ipsec_set_policy(NULL)", __func__);
117		return (-1);
118	}
119	switch (af) {
120	case AF_INET:
121		sd = socket(AF_INET, SOCK_DGRAM, 0);
122		if (sd < 0) {
123			warn("%s: socket4", __func__);
124			return (-1);
125		}
126		break;
127#ifdef INET6
128	case AF_INET6:
129		sd = socket(AF_INET6, SOCK_DGRAM, 0);
130		if (sd < 0) {
131			warn("%s: socket6", __func__);
132			return (-1);
133		}
134		break;
135#endif
136	default:
137		warnx("%s: unexpected address family", __func__);
138		return (-1);
139	}
140	return (0);
141}
142
143int
144priv_netinet_ipsec_policy4_entrust_setup(int asroot, int injail,
145    struct test *test)
146{
147
148	return (priv_netinet_ipsec_policy_entrust_setup_af(asroot, injail, test,
149	    AF_INET));
150}
151
152#ifdef INET6
153int
154priv_netinet_ipsec_policy6_entrust_setup(int asroot, int injail,
155    struct test *test)
156{
157
158	return (priv_netinet_ipsec_policy_entrust_setup_af(asroot, injail, test,
159	    AF_INET6));
160}
161#endif
162
163void
164priv_netinet_ipsec_pfkey(int asroot, int injail, struct test *test)
165{
166	int error, fd;
167
168	fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
169	if (fd < 0)
170		error = -1;
171	else
172		error = 0;
173	/*
174	 * The injail checks are not really priv checks but making sure
175	 * sys/kern/uipc_socket.c:socreate cred checks are working correctly.
176	 */
177	if (asroot && injail)
178		expect("priv_netinet_ipsec_pfkey(asroot, injail)", error,
179		    -1, EPROTONOSUPPORT);
180	if (asroot && !injail)
181		expect("priv_netinet_ipsec_pfkey(asroot, !injail)", error,
182		    0, 0);
183	if (!asroot && injail)
184		expect("priv_netinet_ipsec_pfkey(!asroot, injail)", error,
185		    -1, EPROTONOSUPPORT);
186	if (!asroot && !injail)
187		expect("priv_netinet_ipsec_pfkey(!asroot, !injail)", error,
188		    -1, EPERM);
189	if (fd >= 0)
190		(void)close(fd);
191}
192
193
194static void
195priv_netinet_ipsec_policy_bypass_af(int asroot, int injail, struct test *test,
196    int af)
197{
198	int error, level, optname;
199
200	switch (af) {
201	case AF_INET:
202		level = IPPROTO_IP;
203		optname = IP_IPSEC_POLICY;
204		break;
205#ifdef INET6
206	case AF_INET6:
207		level = IPPROTO_IPV6;
208		optname = IPV6_IPSEC_POLICY;
209		break;
210#endif
211	default:
212		warnx("%s: unexpected address family", __func__);
213		return;
214	}
215	error = setsockopt(sd, level, optname,
216	    bypassbuf, ipsec_get_policylen(bypassbuf));
217	if (asroot && injail)
218		expect("priv_netinet_ipsec_policy_bypass(asroot, injail)",
219		    error, -1, EACCES); /* see ipsec_set_policy */
220	if (asroot && !injail)
221		expect("priv_netinet_ipsec_policy_bypass(asroot, !injail)",
222		    error, 0, 0);
223	if (!asroot && injail)
224		expect("priv_netinet_ipsec_policy_bypass(!asroot, injail)",
225		    error, -1, EACCES); /* see ipsec_set_policy */
226	if (!asroot && !injail)
227		expect("priv_netinet_ipsec_policy_bypass(!asroot, !injail)",
228		    error, -1, EACCES); /* see ipsec_set_policy */
229}
230
231void
232priv_netinet_ipsec_policy4_bypass(int asroot, int injail, struct test *test)
233{
234
235	priv_netinet_ipsec_policy_bypass_af(asroot, injail, test, AF_INET);
236}
237
238#ifdef INET6
239void
240priv_netinet_ipsec_policy6_bypass(int asroot, int injail, struct test *test)
241{
242
243	priv_netinet_ipsec_policy_bypass_af(asroot, injail, test, AF_INET6);
244}
245#endif
246
247static void
248priv_netinet_ipsec_policy_entrust_af(int asroot, int injail, struct test *test,
249    int af)
250{
251	int error, level, optname;
252
253	switch (af) {
254	case AF_INET:
255		level = IPPROTO_IP;
256		optname = IP_IPSEC_POLICY;
257		break;
258#ifdef INET6
259	case AF_INET6:
260		level = IPPROTO_IPV6;
261		optname = IPV6_IPSEC_POLICY;
262		break;
263#endif
264	default:
265		warnx("%s: unexpected address family", __func__);
266		return;
267	}
268	error = setsockopt(sd, level, optname,
269	    entrustbuf, ipsec_get_policylen(entrustbuf));
270	if (asroot && injail)
271		expect("priv_netinet_ipsec_policy_entrust(asroot, injail)",
272		    error, 0, 0); /* XXX ipsec_set_policy */
273	if (asroot && !injail)
274		expect("priv_netinet_ipsec_policy_entrust(asroot, !injail)",
275		    error, 0, 0);
276	if (!asroot && injail)
277		expect("priv_netinet_ipsec_policy_entrust(!asroot, injail)",
278		    error, 0, 0); /* XXX ipsec_set_policy */
279	if (!asroot && !injail)
280		expect("priv_netinet_ipsec_policy_entrust(!asroot, !injail)",
281		    error, 0, 0); /* XXX ipsec_set_policy */
282}
283
284void
285priv_netinet_ipsec_policy4_entrust(int asroot, int injail, struct test *test)
286{
287
288	priv_netinet_ipsec_policy_entrust_af(asroot, injail, test, AF_INET);
289}
290
291#ifdef INET6
292void
293priv_netinet_ipsec_policy6_entrust(int asroot, int injail, struct test *test)
294{
295
296	priv_netinet_ipsec_policy_entrust_af(asroot, injail, test, AF_INET6);
297}
298#endif
299
300void
301priv_netinet_ipsec_policy_bypass_cleanup(int asroot, int injail,
302    struct test *test)
303{
304
305	if (bypassbuf != NULL) {
306		free(bypassbuf);
307		bypassbuf = NULL;
308	}
309	if (sd >= 0) {
310		close(sd);
311		sd = -1;
312	}
313}
314
315void
316priv_netinet_ipsec_policy_entrust_cleanup(int asroot, int injail,
317    struct test *test)
318{
319
320	if (entrustbuf != NULL) {
321		free(entrustbuf);
322		entrustbuf = NULL;
323	}
324	if (sd >= 0) {
325		close(sd);
326		sd = -1;
327	}
328}
329
330