1 /*	$OpenBSD: pfkey.c,v 1.14 2003/02/16 21:30:13 deraadt Exp $	*/
2 
3 /*
4  *	@(#)COPYRIGHT	1.1 (NRL) 17 January 1995
5  *
6  * NRL grants permission for redistribution and use in source and binary
7  * forms, with or without modification, of the software and documentation
8  * created at NRL provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgements:
17  * 	This product includes software developed by the University of
18  * 	California, Berkeley and its contributors.
19  * 	This product includes software developed at the Information
20  * 	Technology Division, US Naval Research Laboratory.
21  * 4. Neither the name of the NRL nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
26  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * The views and conclusions contained in the software and documentation
38  * are those of the authors and should not be interpreted as representing
39  * official policies, either expressed or implied, of the US Naval
40  * Research Laboratory (NRL).
41  */
42 
43 /*
44  * Copyright (c) 1995, 1996, 1997, 1998, 1999 Craig Metz. All rights reserved.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. Neither the name of the author nor the names of any contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  */
70 
71 #include <sys/types.h>
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/socket.h>
75 #include <sys/mbuf.h>
76 #include <sys/socketvar.h>
77 #include <net/route.h>
78 #include <netinet/ip_ipsp.h>
79 #include <net/pfkeyv2.h>
80 
81 #include <sys/protosw.h>
82 #include <sys/domain.h>
83 #include <net/raw_cb.h>
84 
85 #define PFKEY_PROTOCOL_MAX 3
86 static struct pfkey_version *pfkey_versions[PFKEY_PROTOCOL_MAX+1] =
87     { NULL, NULL, NULL, NULL };
88 
89 #define PFKEY_MSG_MAXSZ 4096
90 
91 struct sockaddr pfkey_addr = { 2, PF_KEY, };
92 
93 /* static struct domain pfkey_domain; */
94 static int pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf,
95     struct mbuf *nam, struct mbuf *control);
96 static int pfkey_output(struct mbuf *mbuf, struct socket *socket);
97 
98 int pfkey_register(struct pfkey_version *version);
99 int pfkey_unregister(struct pfkey_version *version);
100 int pfkey_sendup(struct socket *socket, struct mbuf *packet, int more);
101 void pfkey_init(void);
102 int pfkey_buildprotosw(void);
103 
104 int
pfkey_register(struct pfkey_version * version)105 pfkey_register(struct pfkey_version *version)
106 {
107 	int rval;
108 
109 	if ((version->protocol > PFKEY_PROTOCOL_MAX) ||
110 	    (version->protocol < 0))
111 		return (EPROTONOSUPPORT);
112 
113 	if (pfkey_versions[version->protocol])
114 		return (EADDRINUSE);
115 
116 	pfkey_versions[version->protocol] = version;
117 
118 	if ((rval = pfkey_buildprotosw()) != 0) {
119 		pfkey_versions[version->protocol] = NULL;
120 		return (rval);
121 	}
122 
123 	return (0);
124 }
125 
126 int
pfkey_unregister(struct pfkey_version * version)127 pfkey_unregister(struct pfkey_version *version)
128 {
129 	int rval;
130 
131 	if ((rval = pfkey_buildprotosw()) != 0)
132 		return (rval);
133 
134 	pfkey_versions[version->protocol] = NULL;
135 	return (0);
136 }
137 
138 int
pfkey_sendup(struct socket * socket,struct mbuf * packet,int more)139 pfkey_sendup(struct socket *socket, struct mbuf *packet, int more)
140 {
141 	struct mbuf *packet2;
142 	int s;
143 
144 	if (more) {
145 		if (!(packet2 = m_copym2(packet, 0, M_COPYALL, M_DONTWAIT)))
146 			return (ENOMEM);
147 	} else
148 	  packet2 = packet;
149 
150 	s = spltdb();
151 	if (!sbappendaddr(&socket->so_rcv, &pfkey_addr, packet2, NULL)) {
152 		m_freem(packet2);
153 		splx(s);
154 		return (ENOBUFS);
155 	}
156 	splx(s);
157 
158 	sorwakeup(socket);
159 	return (0);
160 }
161 
162 static int
pfkey_output(struct mbuf * mbuf,struct socket * socket)163 pfkey_output(struct mbuf *mbuf, struct socket *socket)
164 {
165 	void *message;
166 	int error = 0;
167 
168 #if DIAGNOSTIC
169 	if (!mbuf || !(mbuf->m_flags & M_PKTHDR)) {
170 		error = EINVAL;
171 		goto ret;
172 	}
173 #endif /* DIAGNOSTIC */
174 
175 	if (mbuf->m_pkthdr.len > PFKEY_MSG_MAXSZ) {
176 		error = EMSGSIZE;
177 		goto ret;
178 	}
179 
180 	if (!(message = malloc((unsigned long) mbuf->m_pkthdr.len,
181 	    M_PFKEY, M_DONTWAIT))) {
182 		error = ENOMEM;
183 		goto ret;
184 	}
185 
186 	m_copydata(mbuf, 0, mbuf->m_pkthdr.len, message);
187 
188 	error = pfkey_versions[socket->so_proto->pr_protocol]->send(socket,
189 	    message, mbuf->m_pkthdr.len);
190 
191 ret:
192 	if (mbuf)
193 		m_freem (mbuf);
194 	return (error);
195 }
196 
197 static int
pfkey_attach(struct socket * socket,struct mbuf * proto)198 pfkey_attach(struct socket *socket, struct mbuf *proto)
199 {
200 	int rval;
201 	int s;
202 
203 	if (!(socket->so_pcb = malloc(sizeof(struct rawcb),
204 	    M_PCB, M_DONTWAIT)))
205 		return (ENOMEM);
206 	bzero(socket->so_pcb, sizeof(struct rawcb));
207 
208 	s = splnet();
209 	rval = raw_usrreq(socket, PRU_ATTACH, NULL, proto, NULL);
210 	splx(s);
211 	if (rval)
212 		goto ret;
213 
214 	((struct rawcb *)socket->so_pcb)->rcb_faddr = &pfkey_addr;
215 	soisconnected(socket);
216 
217 	socket->so_options |= SO_USELOOPBACK;
218 	if ((rval =
219 	    pfkey_versions[socket->so_proto->pr_protocol]->create(socket)) != 0)
220 		goto ret;
221 
222 	return (0);
223 
224 ret:
225 	free(socket->so_pcb, M_PCB);
226 	return (rval);
227 }
228 
229 static int
pfkey_detach(struct socket * socket)230 pfkey_detach(struct socket *socket)
231 {
232 	int rval, i, s;
233 
234 	rval = pfkey_versions[socket->so_proto->pr_protocol]->release(socket);
235 	s = splnet();
236 	i = raw_usrreq(socket, PRU_DETACH, NULL, NULL, NULL);
237 	splx(s);
238 
239 	if (!rval)
240 		rval = i;
241 
242 	return (rval);
243 }
244 
245 static int
pfkey_usrreq(struct socket * socket,int req,struct mbuf * mbuf,struct mbuf * nam,struct mbuf * control)246 pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf,
247     struct mbuf *nam, struct mbuf *control)
248 {
249 	int rval;
250 	int s;
251 
252 	if ((socket->so_proto->pr_protocol > PFKEY_PROTOCOL_MAX) ||
253 	    (socket->so_proto->pr_protocol < 0) ||
254 	    !pfkey_versions[socket->so_proto->pr_protocol])
255 		return (EPROTONOSUPPORT);
256 
257 	switch (req) {
258 	case PRU_ATTACH:
259 		return (pfkey_attach(socket, nam));
260 
261 	case PRU_DETACH:
262 		return (pfkey_detach(socket));
263 
264 	default:
265 		s = splnet();
266 		rval = raw_usrreq(socket, req, mbuf, nam, control);
267 		splx(s);
268 	}
269 
270 	return (rval);
271 }
272 
273 static struct domain pfkey_domain = {
274 	PF_KEY,
275 	"PF_KEY",
276 	NULL, /* init */
277 	NULL, /* externalize */
278 	NULL, /* dispose */
279 	NULL, /* protosw */
280 	NULL, /* protoswNPROTOSW */
281 	NULL, /* dom_next */
282 	rn_inithead, /* dom_rtattach */
283 	16, /* rtoffset */
284 	sizeof(struct sockaddr_encap)  /* maxrtkey */
285 };
286 
287 static struct protosw pfkey_protosw_template = {
288 	SOCK_RAW,
289 	&pfkey_domain,
290 	-1, /* protocol */
291 	PR_ATOMIC | PR_ADDR,
292 	(void *) raw_input,
293 	(void *) pfkey_output,
294 	(void *) raw_ctlinput,
295 	NULL, /* ctloutput */
296 	pfkey_usrreq,
297 	NULL, /* init */
298 	NULL, /* fasttimo */
299 	NULL, /* slowtimo */
300 	NULL, /* drain */
301 	NULL	/* sysctl */
302 };
303 
304 int
pfkey_buildprotosw(void)305 pfkey_buildprotosw(void)
306 {
307 	struct protosw *protosw, *p;
308 	int i, j;
309 
310 	for (i = j = 0; i <= PFKEY_PROTOCOL_MAX; i++)
311 		if (pfkey_versions[i])
312 			j++;
313 
314 	if (j) {
315 		if (!(protosw = malloc(j * sizeof(struct protosw),
316 		    M_PFKEY, M_DONTWAIT)))
317 			return (ENOMEM);
318 
319 		for (i = 0, p = protosw; i <= PFKEY_PROTOCOL_MAX; i++)
320 			if (pfkey_versions[i]) {
321 				bcopy(&pfkey_protosw_template, p,
322 				    sizeof(struct protosw));
323 				p->pr_protocol = pfkey_versions[i]->protocol;
324 				p++;
325 			}
326 
327 		if (pfkey_domain.dom_protosw)
328 			free(pfkey_domain.dom_protosw, M_PFKEY);
329 
330 		pfkey_domain.dom_protosw = protosw;
331 		pfkey_domain.dom_protoswNPROTOSW = p;
332 	} else {
333 		if (!(protosw = malloc(sizeof(struct protosw), M_PFKEY,
334 		    M_DONTWAIT)))
335 			return (ENOMEM);
336 
337 		bcopy(&pfkey_protosw_template, protosw,
338 		    sizeof(struct protosw));
339 
340 		if (pfkey_domain.dom_protosw)
341 			free(pfkey_domain.dom_protosw, M_PFKEY);
342 
343 		pfkey_domain.dom_protosw = protosw;
344 		pfkey_domain.dom_protoswNPROTOSW = protosw;
345 	}
346 
347 	return (0);
348 }
349 
350 void
pfkey_init(void)351 pfkey_init(void)
352 {
353 	if (pfkey_buildprotosw() != 0)
354 		return;
355 
356 	pfkey_domain.dom_next = domains;
357 	domains = &pfkey_domain;
358 	pfkeyv2_init();
359 }
360