1/*-
2 * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
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 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28#include "opt_inet.h"
29#include "opt_inet6.h"
30#include "opt_ipsec.h"
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/lock.h>
36#include <sys/malloc.h>
37#include <sys/mbuf.h>
38#include <sys/priv.h>
39#include <sys/socket.h>
40#include <sys/sockopt.h>
41#include <sys/syslog.h>
42#include <sys/proc.h>
43
44#include <netinet/in.h>
45#include <netinet/in_pcb.h>
46
47#include <netipsec/ipsec.h>
48#include <netipsec/ipsec6.h>
49#include <netipsec/ipsec_support.h>
50#include <netipsec/key.h>
51#include <netipsec/key_debug.h>
52
53MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy");
54
55static void
56ipsec_setsockaddrs_inpcb(struct inpcb *inp, union sockaddr_union *src,
57    union sockaddr_union *dst, u_int dir)
58{
59
60#ifdef INET6
61	if (inp->inp_vflag & INP_IPV6) {
62		struct sockaddr_in6 *sin6;
63
64		bzero(&src->sin6, sizeof(src->sin6));
65		bzero(&dst->sin6, sizeof(dst->sin6));
66		src->sin6.sin6_family = AF_INET6;
67		src->sin6.sin6_len = sizeof(struct sockaddr_in6);
68		dst->sin6.sin6_family = AF_INET6;
69		dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
70
71		if (dir == IPSEC_DIR_OUTBOUND)
72			sin6 = &src->sin6;
73		else
74			sin6 = &dst->sin6;
75		sin6->sin6_addr = inp->in6p_laddr;
76		sin6->sin6_port = inp->inp_lport;
77		if (IN6_IS_SCOPE_LINKLOCAL(&inp->in6p_laddr)) {
78			/* XXXAE: use in6p_zoneid */
79			sin6->sin6_addr.s6_addr16[1] = 0;
80			sin6->sin6_scope_id = ntohs(
81			    inp->in6p_laddr.s6_addr16[1]);
82		}
83
84		if (dir == IPSEC_DIR_OUTBOUND)
85			sin6 = &dst->sin6;
86		else
87			sin6 = &src->sin6;
88		sin6->sin6_addr = inp->in6p_faddr;
89		sin6->sin6_port = inp->inp_fport;
90		if (IN6_IS_SCOPE_LINKLOCAL(&inp->in6p_faddr)) {
91			/* XXXAE: use in6p_zoneid */
92			sin6->sin6_addr.s6_addr16[1] = 0;
93			sin6->sin6_scope_id = ntohs(
94			    inp->in6p_faddr.s6_addr16[1]);
95		}
96	}
97#endif
98#ifdef INET
99	if (inp->inp_vflag & INP_IPV4) {
100		struct sockaddr_in *sin;
101
102		bzero(&src->sin, sizeof(src->sin));
103		bzero(&dst->sin, sizeof(dst->sin));
104		src->sin.sin_family = AF_INET;
105		src->sin.sin_len = sizeof(struct sockaddr_in);
106		dst->sin.sin_family = AF_INET;
107		dst->sin.sin_len = sizeof(struct sockaddr_in);
108
109		if (dir == IPSEC_DIR_OUTBOUND)
110			sin = &src->sin;
111		else
112			sin = &dst->sin;
113		sin->sin_addr = inp->inp_laddr;
114		sin->sin_port = inp->inp_lport;
115
116		if (dir == IPSEC_DIR_OUTBOUND)
117			sin = &dst->sin;
118		else
119			sin = &src->sin;
120		sin->sin_addr = inp->inp_faddr;
121		sin->sin_port = inp->inp_fport;
122	}
123#endif
124}
125
126void
127ipsec_setspidx_inpcb(struct inpcb *inp, struct secpolicyindex *spidx,
128    u_int dir)
129{
130
131	ipsec_setsockaddrs_inpcb(inp, &spidx->src, &spidx->dst, dir);
132#ifdef INET6
133	if (inp->inp_vflag & INP_IPV6) {
134		spidx->prefs = sizeof(struct in6_addr) << 3;
135		spidx->prefd = sizeof(struct in6_addr) << 3;
136	}
137#endif
138#ifdef INET
139	if (inp->inp_vflag & INP_IPV4) {
140		spidx->prefs = sizeof(struct in_addr) << 3;
141		spidx->prefd = sizeof(struct in_addr) << 3;
142	}
143#endif
144	spidx->ul_proto = IPPROTO_TCP; /* XXX: currently only TCP uses this */
145	spidx->dir = dir;
146	KEYDBG(IPSEC_DUMP,
147	    printf("%s: ", __func__); kdebug_secpolicyindex(spidx, NULL));
148}
149
150/* Initialize PCB policy. */
151int
152ipsec_init_pcbpolicy(struct inpcb *inp)
153{
154
155	IPSEC_ASSERT(inp != NULL, ("null inp"));
156	IPSEC_ASSERT(inp->inp_sp == NULL, ("inp_sp already initialized"));
157
158	inp->inp_sp = malloc(sizeof(struct inpcbpolicy), M_IPSEC_INPCB,
159	    M_NOWAIT | M_ZERO);
160	if (inp->inp_sp == NULL)
161		return (ENOBUFS);
162	return (0);
163}
164
165/* Delete PCB policy. */
166int
167ipsec_delete_pcbpolicy(struct inpcb *inp)
168{
169
170	if (inp->inp_sp == NULL)
171		return (0);
172
173	if (inp->inp_sp->sp_in != NULL)
174		key_freesp(&inp->inp_sp->sp_in);
175
176	if (inp->inp_sp->sp_out != NULL)
177		key_freesp(&inp->inp_sp->sp_out);
178
179	free(inp->inp_sp, M_IPSEC_INPCB);
180	inp->inp_sp = NULL;
181	return (0);
182}
183
184/* Deep-copy a policy in PCB. */
185static struct secpolicy *
186ipsec_deepcopy_pcbpolicy(struct secpolicy *src)
187{
188	struct secpolicy *dst;
189	int i;
190
191	if (src == NULL)
192		return (NULL);
193
194	IPSEC_ASSERT(src->state == IPSEC_SPSTATE_PCB, ("SP isn't PCB"));
195
196	dst = key_newsp();
197	if (dst == NULL)
198		return (NULL);
199
200	/* spidx is not copied here */
201	dst->policy = src->policy;
202	dst->state = src->state;
203	dst->priority = src->priority;
204	/* Do not touch the refcnt field. */
205
206	/* Copy IPsec request chain. */
207	for (i = 0; i < src->tcount; i++) {
208		dst->req[i] = ipsec_newisr();
209		if (dst->req[i] == NULL) {
210			key_freesp(&dst);
211			return (NULL);
212		}
213		bcopy(src->req[i], dst->req[i], sizeof(struct ipsecrequest));
214		dst->tcount++;
215	}
216	KEYDBG(IPSEC_DUMP,
217	    printf("%s: copied SP(%p) -> SP(%p)\n", __func__, src, dst);
218	    kdebug_secpolicy(dst));
219	return (dst);
220}
221
222/*
223 * Copy IPsec policy from old INPCB into new.
224 * It is expected that new INPCB has not configured policies.
225 */
226int
227ipsec_copy_pcbpolicy(struct inpcb *old, struct inpcb *new)
228{
229	struct secpolicy *sp;
230
231	/*
232	 * old->inp_sp can be NULL if PCB was created when an IPsec
233	 * support was unavailable. This is not an error, we don't have
234	 * policies in this PCB, so nothing to copy.
235	 */
236	if (old->inp_sp == NULL)
237		return (0);
238
239	IPSEC_ASSERT(new->inp_sp != NULL, ("new inp_sp is NULL"));
240	IPSEC_ASSERT((new->inp_sp->flags & (
241	    INP_INBOUND_POLICY | INP_OUTBOUND_POLICY)) == 0,
242	    ("new PCB already has configured policies"));
243	INP_WLOCK_ASSERT(new);
244	INP_LOCK_ASSERT(old);
245
246	if (old->inp_sp->flags & INP_INBOUND_POLICY) {
247		sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_in);
248		if (sp == NULL)
249			return (ENOBUFS);
250		ipsec_setspidx_inpcb(new, &sp->spidx, IPSEC_DIR_INBOUND);
251		if (new->inp_sp->sp_in != NULL)
252			key_freesp(&new->inp_sp->sp_in);
253		new->inp_sp->sp_in = sp;
254		new->inp_sp->flags |= INP_INBOUND_POLICY;
255	}
256	if (old->inp_sp->flags & INP_OUTBOUND_POLICY) {
257		sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_out);
258		if (sp == NULL)
259			return (ENOBUFS);
260		ipsec_setspidx_inpcb(new, &sp->spidx, IPSEC_DIR_OUTBOUND);
261		if (new->inp_sp->sp_out != NULL)
262			key_freesp(&new->inp_sp->sp_out);
263		new->inp_sp->sp_out = sp;
264		new->inp_sp->flags |= INP_OUTBOUND_POLICY;
265	}
266	return (0);
267}
268
269static int
270ipsec_set_pcbpolicy(struct inpcb *inp, struct ucred *cred,
271    void *request, size_t len)
272{
273	struct sadb_x_policy *xpl;
274	struct secpolicy **spp, *newsp;
275	int error, flags;
276
277	xpl = (struct sadb_x_policy *)request;
278	/* Select direction. */
279	switch (xpl->sadb_x_policy_dir) {
280	case IPSEC_DIR_INBOUND:
281	case IPSEC_DIR_OUTBOUND:
282		break;
283	default:
284		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
285			xpl->sadb_x_policy_dir));
286		return (EINVAL);
287	}
288	/*
289	 * Privileged sockets are allowed to set own security policy
290	 * and configure IPsec bypass. Unprivileged sockets only can
291	 * have ENTRUST policy.
292	 */
293	switch (xpl->sadb_x_policy_type) {
294	case IPSEC_POLICY_IPSEC:
295	case IPSEC_POLICY_BYPASS:
296		if (cred != NULL &&
297		    priv_check_cred(cred, PRIV_NETINET_IPSEC) != 0)
298			return (EACCES);
299		/* Allocate new SP entry. */
300		newsp = key_msg2sp(xpl, len, &error);
301		if (newsp == NULL)
302			return (error);
303		newsp->state = IPSEC_SPSTATE_PCB;
304		newsp->spidx.ul_proto = IPSEC_ULPROTO_ANY;
305#ifdef INET
306		if (inp->inp_vflag & INP_IPV4) {
307			newsp->spidx.src.sin.sin_family =
308			    newsp->spidx.dst.sin.sin_family = AF_INET;
309			newsp->spidx.src.sin.sin_len =
310			    newsp->spidx.dst.sin.sin_len =
311			    sizeof(struct sockaddr_in);
312		}
313#endif
314#ifdef INET6
315		if (inp->inp_vflag & INP_IPV6) {
316			newsp->spidx.src.sin6.sin6_family =
317			    newsp->spidx.dst.sin6.sin6_family = AF_INET6;
318			newsp->spidx.src.sin6.sin6_len =
319			    newsp->spidx.dst.sin6.sin6_len =
320			    sizeof(struct sockaddr_in6);
321		}
322#endif
323		break;
324	case IPSEC_POLICY_ENTRUST:
325		/* We just use NULL pointer for ENTRUST policy */
326		newsp = NULL;
327		break;
328	default:
329		/* Other security policy types aren't allowed for PCB */
330		return (EINVAL);
331	}
332
333	INP_WLOCK(inp);
334	if (xpl->sadb_x_policy_dir == IPSEC_DIR_INBOUND) {
335		spp = &inp->inp_sp->sp_in;
336		flags = INP_INBOUND_POLICY;
337	} else {
338		spp = &inp->inp_sp->sp_out;
339		flags = INP_OUTBOUND_POLICY;
340	}
341	/* Clear old SP and set new SP. */
342	if (*spp != NULL)
343		key_freesp(spp);
344	*spp = newsp;
345	KEYDBG(IPSEC_DUMP,
346	    printf("%s: new SP(%p)\n", __func__, newsp));
347	if (newsp == NULL)
348		inp->inp_sp->flags &= ~flags;
349	else {
350		inp->inp_sp->flags |= flags;
351		KEYDBG(IPSEC_DUMP, kdebug_secpolicy(newsp));
352	}
353	INP_WUNLOCK(inp);
354	return (0);
355}
356
357static int
358ipsec_get_pcbpolicy(struct inpcb *inp, void *request, size_t *len)
359{
360	struct sadb_x_policy *xpl;
361	struct secpolicy *sp;
362	int error, flags;
363
364	xpl = (struct sadb_x_policy *)request;
365
366	INP_RLOCK(inp);
367	flags = inp->inp_sp->flags;
368	/* Select direction. */
369	switch (xpl->sadb_x_policy_dir) {
370	case IPSEC_DIR_INBOUND:
371		sp = inp->inp_sp->sp_in;
372		flags &= INP_INBOUND_POLICY;
373		break;
374	case IPSEC_DIR_OUTBOUND:
375		sp = inp->inp_sp->sp_out;
376		flags &= INP_OUTBOUND_POLICY;
377		break;
378	default:
379		INP_RUNLOCK(inp);
380		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
381			xpl->sadb_x_policy_dir));
382		return (EINVAL);
383	}
384
385	if (flags == 0) {
386		/* Return ENTRUST policy */
387		INP_RUNLOCK(inp);
388		xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
389		xpl->sadb_x_policy_type = IPSEC_POLICY_ENTRUST;
390		xpl->sadb_x_policy_id = 0;
391		xpl->sadb_x_policy_priority = 0;
392		xpl->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*xpl));
393		*len = sizeof(*xpl);
394		return (0);
395	}
396
397	IPSEC_ASSERT(sp != NULL,
398	    ("sp is NULL, but flags is 0x%04x", inp->inp_sp->flags));
399
400	key_addref(sp);
401	INP_RUNLOCK(inp);
402	error = key_sp2msg(sp, request, len);
403	key_freesp(&sp);
404	if (error == EINVAL)
405		return (error);
406	/*
407	 * We return "success", but user should check *len.
408	 * *len will be set to size of valid data and
409	 * sadb_x_policy_len will contain needed size.
410	 */
411	return (0);
412}
413
414/* Handle socket option control request for PCB */
415static int
416ipsec_control_pcbpolicy(struct inpcb *inp, struct sockopt *sopt)
417{
418	void *optdata;
419	size_t optlen;
420	int error;
421
422	if (inp->inp_sp == NULL)
423		return (ENOPROTOOPT);
424
425	/* Limit maximum request size to PAGE_SIZE */
426	optlen = sopt->sopt_valsize;
427	if (optlen < sizeof(struct sadb_x_policy) || optlen > PAGE_SIZE)
428		return (EINVAL);
429
430	optdata = malloc(optlen, M_TEMP, sopt->sopt_td ? M_WAITOK: M_NOWAIT);
431	if (optdata == NULL)
432		return (ENOBUFS);
433	/*
434	 * We need a hint from the user, what policy is requested - input
435	 * or output? User should specify it in the buffer, even for
436	 * setsockopt().
437	 */
438	error = sooptcopyin(sopt, optdata, optlen, optlen);
439	if (error == 0) {
440		if (sopt->sopt_dir == SOPT_SET)
441			error = ipsec_set_pcbpolicy(inp,
442			    sopt->sopt_td ? sopt->sopt_td->td_ucred: NULL,
443			    optdata, optlen);
444		else {
445			error = ipsec_get_pcbpolicy(inp, optdata, &optlen);
446			if (error == 0)
447				error = sooptcopyout(sopt, optdata, optlen);
448		}
449	}
450	free(optdata, M_TEMP);
451	return (error);
452}
453
454#ifdef INET
455/*
456 * IPSEC_PCBCTL() method implementation for IPv4.
457 */
458int
459ipsec4_pcbctl(struct inpcb *inp, struct sockopt *sopt)
460{
461
462	if (sopt->sopt_name != IP_IPSEC_POLICY)
463		return (ENOPROTOOPT);
464	return (ipsec_control_pcbpolicy(inp, sopt));
465}
466#endif
467
468#ifdef INET6
469/*
470 * IPSEC_PCBCTL() method implementation for IPv6.
471 */
472int
473ipsec6_pcbctl(struct inpcb *inp, struct sockopt *sopt)
474{
475
476	if (sopt->sopt_name != IPV6_IPSEC_POLICY)
477		return (ENOPROTOOPT);
478	return (ipsec_control_pcbpolicy(inp, sopt));
479}
480#endif
481