xref: /openbsd/sys/net/pfkeyv2_parsemessage.c (revision 91f110e0)
1 /*	$OpenBSD: pfkeyv2_parsemessage.c,v 1.47 2013/04/10 08:50:59 mpi 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 "pf.h"
72 
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/socket.h>
76 #include <sys/mbuf.h>
77 #include <sys/proc.h>
78 #include <netinet/ip_ipsp.h>
79 #include <netinet/ip_var.h>
80 #include <net/pfkeyv2.h>
81 
82 #if NPF > 0
83 #include <net/if.h>
84 #include <net/pfvar.h>
85 #endif
86 
87 #ifdef ENCDEBUG
88 #define DPRINTF(x)	if (encdebug) printf x
89 #else
90 #define DPRINTF(x)
91 #endif
92 
93 #define BITMAP_SA                      (1LL << SADB_EXT_SA)
94 #define BITMAP_LIFETIME_CURRENT        (1LL << SADB_EXT_LIFETIME_CURRENT)
95 #define BITMAP_LIFETIME_HARD           (1LL << SADB_EXT_LIFETIME_HARD)
96 #define BITMAP_LIFETIME_SOFT           (1LL << SADB_EXT_LIFETIME_SOFT)
97 #define BITMAP_ADDRESS_SRC             (1LL << SADB_EXT_ADDRESS_SRC)
98 #define BITMAP_ADDRESS_DST             (1LL << SADB_EXT_ADDRESS_DST)
99 #define BITMAP_ADDRESS_PROXY           (1LL << SADB_EXT_ADDRESS_PROXY)
100 #define BITMAP_KEY_AUTH                (1LL << SADB_EXT_KEY_AUTH)
101 #define BITMAP_KEY_ENCRYPT             (1LL << SADB_EXT_KEY_ENCRYPT)
102 #define BITMAP_IDENTITY_SRC            (1LL << SADB_EXT_IDENTITY_SRC)
103 #define BITMAP_IDENTITY_DST            (1LL << SADB_EXT_IDENTITY_DST)
104 #define BITMAP_SENSITIVITY             (1LL << SADB_EXT_SENSITIVITY)
105 #define BITMAP_PROPOSAL                (1LL << SADB_EXT_PROPOSAL)
106 #define BITMAP_SUPPORTED_AUTH          (1LL << SADB_EXT_SUPPORTED_AUTH)
107 #define BITMAP_SUPPORTED_ENCRYPT       (1LL << SADB_EXT_SUPPORTED_ENCRYPT)
108 #define BITMAP_SPIRANGE                (1LL << SADB_EXT_SPIRANGE)
109 #define BITMAP_LIFETIME (BITMAP_LIFETIME_CURRENT | BITMAP_LIFETIME_HARD | BITMAP_LIFETIME_SOFT)
110 #define BITMAP_ADDRESS (BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_ADDRESS_PROXY)
111 #define BITMAP_KEY      (BITMAP_KEY_AUTH | BITMAP_KEY_ENCRYPT)
112 #define BITMAP_IDENTITY (BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST)
113 #define BITMAP_MSG                     1
114 #define BITMAP_X_SRC_MASK              (1LL << SADB_X_EXT_SRC_MASK)
115 #define BITMAP_X_DST_MASK              (1LL << SADB_X_EXT_DST_MASK)
116 #define BITMAP_X_PROTOCOL              (1LL << SADB_X_EXT_PROTOCOL)
117 #define BITMAP_X_SRC_FLOW              (1LL << SADB_X_EXT_SRC_FLOW)
118 #define BITMAP_X_DST_FLOW              (1LL << SADB_X_EXT_DST_FLOW)
119 #define BITMAP_X_FLOW_TYPE             (1LL << SADB_X_EXT_FLOW_TYPE)
120 #define BITMAP_X_SA2                   (1LL << SADB_X_EXT_SA2)
121 #define BITMAP_X_DST2                  (1LL << SADB_X_EXT_DST2)
122 #define BITMAP_X_POLICY                (1LL << SADB_X_EXT_POLICY)
123 #define BITMAP_X_LOCAL_CREDENTIALS     (1LL << SADB_X_EXT_LOCAL_CREDENTIALS)
124 #define BITMAP_X_REMOTE_CREDENTIALS    (1LL << SADB_X_EXT_REMOTE_CREDENTIALS)
125 #define BITMAP_X_LOCAL_AUTH            (1LL << SADB_X_EXT_LOCAL_AUTH)
126 #define BITMAP_X_REMOTE_AUTH           (1LL << SADB_X_EXT_REMOTE_AUTH)
127 #define BITMAP_X_CREDENTIALS           (BITMAP_X_LOCAL_CREDENTIALS | BITMAP_X_REMOTE_CREDENTIALS | BITMAP_X_LOCAL_AUTH | BITMAP_X_REMOTE_AUTH)
128 #define BITMAP_X_FLOW                  (BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE)
129 #define BITMAP_X_SUPPORTED_COMP        (1LL << SADB_X_EXT_SUPPORTED_COMP)
130 #define BITMAP_X_UDPENCAP              (1LL << SADB_X_EXT_UDPENCAP)
131 #define BITMAP_X_LIFETIME_LASTUSE      (1LL << SADB_X_EXT_LIFETIME_LASTUSE)
132 #define BITMAP_X_TAG                   (1LL << SADB_X_EXT_TAG)
133 #define BITMAP_X_TAP                   (1LL << SADB_X_EXT_TAP)
134 
135 uint64_t sadb_exts_allowed_in[SADB_MAX+1] =
136 {
137 	/* RESERVED */
138 	~0,
139 	/* GETSPI */
140 	BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE,
141 	/* UPDATE */
142 	BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP,
143 	/* ADD */
144 	BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_LIFETIME_LASTUSE | BITMAP_X_TAG | BITMAP_X_TAP,
145 	/* DELETE */
146 	BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
147 	/* GET */
148 	BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
149 	/* ACQUIRE */
150 	BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL | BITMAP_X_CREDENTIALS,
151 	/* REGISTER */
152 	0,
153 	/* EXPIRE */
154 	BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
155 	/* FLUSH */
156 	0,
157 	/* DUMP */
158 	0,
159 	/* X_PROMISC */
160 	0,
161 	/* X_ADDFLOW */
162 	BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST | BITMAP_X_FLOW,
163 	/* X_DELFLOW */
164 	BITMAP_X_FLOW,
165 	/* X_GRPSPIS */
166 	BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL,
167 	/* X_ASKPOLICY */
168 	BITMAP_X_POLICY,
169 };
170 
171 uint64_t sadb_exts_required_in[SADB_MAX+1] =
172 {
173 	/* RESERVED */
174 	0,
175 	/* GETSPI */
176 	BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE,
177 	/* UPDATE */
178 	BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
179 	/* ADD */
180 	BITMAP_SA | BITMAP_ADDRESS_DST,
181 	/* DELETE */
182 	BITMAP_SA | BITMAP_ADDRESS_DST,
183 	/* GET */
184 	BITMAP_SA | BITMAP_ADDRESS_DST,
185 	/* ACQUIRE */
186 	0,
187 	/* REGISTER */
188 	0,
189 	/* EXPIRE */
190 	BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
191 	/* FLUSH */
192 	0,
193 	/* DUMP */
194 	0,
195 	/* X_PROMISC */
196 	0,
197 	/* X_ADDFLOW */
198 	BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE,
199 	/* X_DELFLOW */
200 	BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE,
201 	/* X_GRPSPIS */
202 	BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL,
203 	/* X_ASKPOLICY */
204 	BITMAP_X_POLICY,
205 };
206 
207 uint64_t sadb_exts_allowed_out[SADB_MAX+1] =
208 {
209 	/* RESERVED */
210 	~0,
211 	/* GETSPI */
212 	BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
213 	/* UPDATE */
214 	BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP,
215 	/* ADD */
216 	BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_FLOW | BITMAP_X_UDPENCAP | BITMAP_X_TAG | BITMAP_X_TAP,
217 	/* DELETE */
218 	BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
219 	/* GET */
220 	BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY | BITMAP_X_CREDENTIALS | BITMAP_X_UDPENCAP | BITMAP_X_LIFETIME_LASTUSE | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_FLOW_TYPE | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_TAG | BITMAP_X_TAP,
221 	/* ACQUIRE */
222 	BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL | BITMAP_X_CREDENTIALS,
223 	/* REGISTER */
224 	BITMAP_SUPPORTED_AUTH | BITMAP_SUPPORTED_ENCRYPT | BITMAP_X_SUPPORTED_COMP,
225 	/* EXPIRE */
226 	BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS,
227 	/* FLUSH */
228 	0,
229 	/* DUMP */
230 	BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY,
231 	/* X_PROMISC */
232 	0,
233 	/* X_ADDFLOW */
234 	BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE | BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST,
235 	/* X_DELFLOW */
236 	BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE,
237 	/* X_GRPSPIS */
238 	BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL,
239 	/* X_ASKPOLICY */
240 	BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_FLOW_TYPE | BITMAP_X_POLICY,
241 };
242 
243 uint64_t sadb_exts_required_out[SADB_MAX+1] =
244 {
245 	/* RESERVED */
246 	0,
247 	/* GETSPI */
248 	BITMAP_SA | BITMAP_ADDRESS_DST,
249 	/* UPDATE */
250 	BITMAP_SA | BITMAP_ADDRESS_DST,
251 	/* ADD */
252 	BITMAP_SA | BITMAP_ADDRESS_DST,
253 	/* DELETE */
254 	BITMAP_SA | BITMAP_ADDRESS_DST,
255 	/* GET */
256 	BITMAP_SA | BITMAP_LIFETIME_CURRENT | BITMAP_ADDRESS_DST,
257 	/* ACQUIRE */
258 	0,
259 	/* REGISTER */
260 	BITMAP_SUPPORTED_AUTH | BITMAP_SUPPORTED_ENCRYPT | BITMAP_X_SUPPORTED_COMP,
261 	/* EXPIRE */
262 	BITMAP_SA | BITMAP_ADDRESS_DST,
263 	/* FLUSH */
264 	0,
265 	/* DUMP */
266 	0,
267 	/* X_PROMISC */
268 	0,
269 	/* X_ADDFLOW */
270 	BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE,
271 	/* X_DELFLOW */
272 	BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_FLOW_TYPE,
273 	/* X_GRPSPIS */
274 	BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL,
275 	/* X_REPPOLICY */
276 	BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_FLOW_TYPE,
277 };
278 
279 int pfkeyv2_parsemessage(void *, int, void **);
280 
281 #define RETURN_EINVAL(line) goto einval;
282 
283 int
284 pfkeyv2_parsemessage(void *p, int len, void **headers)
285 {
286 	struct sadb_ext *sadb_ext;
287 	int i, left = len;
288 	uint64_t allow, seen = 1;
289 	struct sadb_msg *sadb_msg = (struct sadb_msg *) p;
290 
291 	bzero(headers, (SADB_EXT_MAX + 1) * sizeof(void *));
292 
293 	if (left < sizeof(struct sadb_msg)) {
294 		DPRINTF(("pfkeyv2_parsemessage: message too short\n"));
295 		return (EINVAL);
296 	}
297 
298 	headers[0] = p;
299 
300 	if (sadb_msg->sadb_msg_len * sizeof(uint64_t) != left) {
301 		DPRINTF(("pfkeyv2_parsemessage: length not a multiple of 64\n"));
302 		return (EINVAL);
303 	}
304 
305 	p += sizeof(struct sadb_msg);
306 	left -= sizeof(struct sadb_msg);
307 
308 	if (sadb_msg->sadb_msg_reserved) {
309 		DPRINTF(("pfkeyv2_parsemessage: message header reserved "
310 		    "field set\n"));
311 		return (EINVAL);
312 	}
313 
314 	if (sadb_msg->sadb_msg_type > SADB_MAX) {
315 		DPRINTF(("pfkeyv2_parsemessage: message type > %d\n",
316 		    SADB_MAX));
317 		return (EINVAL);
318 	}
319 
320 	if (!sadb_msg->sadb_msg_type) {
321 		DPRINTF(("pfkeyv2_parsemessage: message type unset\n"));
322 		return (EINVAL);
323 	}
324 
325 	if (sadb_msg->sadb_msg_pid != curproc->p_p->ps_pid) {
326 		DPRINTF(("pfkeyv2_parsemessage: bad PID value\n"));
327 		return (EINVAL);
328 	}
329 
330 	if (sadb_msg->sadb_msg_errno) {
331 		if (left) {
332 			DPRINTF(("pfkeyv2_parsemessage: too-large error message\n"));
333 			return (EINVAL);
334 		}
335 		return (0);
336 	}
337 
338 	if (sadb_msg->sadb_msg_type == SADB_X_PROMISC) {
339 		DPRINTF(("pfkeyv2_parsemessage: message type promiscuous\n"));
340 		return (0);
341 	}
342 
343 	allow = sadb_exts_allowed_in[sadb_msg->sadb_msg_type];
344 
345 	while (left > 0) {
346 		sadb_ext = (struct sadb_ext *)p;
347 		if (left < sizeof(struct sadb_ext)) {
348 			DPRINTF(("pfkeyv2_parsemessage: extension header too "
349 			    "short\n"));
350 			return (EINVAL);
351 		}
352 
353 		i = sadb_ext->sadb_ext_len * sizeof(uint64_t);
354 		if (left < i) {
355 			DPRINTF(("pfkeyv2_parsemessage: extension header "
356 			    "exceeds message length\n"));
357 			return (EINVAL);
358 		}
359 
360 		if (sadb_ext->sadb_ext_type > SADB_EXT_MAX) {
361 			DPRINTF(("pfkeyv2_parsemessage: unknown extension "
362 			    "header %d\n", sadb_ext->sadb_ext_type));
363 			return (EINVAL);
364 		}
365 
366 		if (!sadb_ext->sadb_ext_type) {
367 			DPRINTF(("pfkeyv2_parsemessage: unset extension "
368 			    "header\n"));
369 			return (EINVAL);
370 		}
371 
372 		if (!(allow & (1LL << sadb_ext->sadb_ext_type))) {
373 			DPRINTF(("pfkeyv2_parsemessage: extension header %d "
374 			    "not permitted on message type %d\n",
375 			    sadb_ext->sadb_ext_type, sadb_msg->sadb_msg_type));
376 			return (EINVAL);
377 		}
378 
379 		if (headers[sadb_ext->sadb_ext_type]) {
380 			DPRINTF(("pfkeyv2_parsemessage: duplicate extension "
381 			    "header %d\n", sadb_ext->sadb_ext_type));
382 			return (EINVAL);
383 		}
384 
385 		seen |= (1LL << sadb_ext->sadb_ext_type);
386 
387 		switch (sadb_ext->sadb_ext_type) {
388 		case SADB_EXT_SA:
389 		case SADB_X_EXT_SA2:
390 		{
391 			struct sadb_sa *sadb_sa = (struct sadb_sa *)p;
392 
393 			if (i != sizeof(struct sadb_sa)) {
394 				DPRINTF(("pfkeyv2_parsemessage: bad header "
395 				    "length for SA extension header %d\n",
396 				    sadb_ext->sadb_ext_type));
397 				return (EINVAL);
398 			}
399 
400 			if (sadb_sa->sadb_sa_state > SADB_SASTATE_MAX) {
401 				DPRINTF(("pfkeyv2_parsemessage: unknown SA "
402 				    "state %d in SA extension header %d\n",
403 				    sadb_sa->sadb_sa_state,
404 				    sadb_ext->sadb_ext_type));
405 				return (EINVAL);
406 			}
407 
408 			if (sadb_sa->sadb_sa_state == SADB_SASTATE_DEAD) {
409 				DPRINTF(("pfkeyv2_parsemessage: cannot set SA "
410 				    "state to dead, SA extension header %d\n",
411 				    sadb_ext->sadb_ext_type));
412 				return (EINVAL);
413 			}
414 
415 			if (sadb_sa->sadb_sa_encrypt > SADB_EALG_MAX) {
416 				DPRINTF(("pfkeyv2_parsemessage: unknown "
417 				    "encryption algorithm %d in SA extension "
418 				    "header %d\n", sadb_sa->sadb_sa_encrypt,
419 				    sadb_ext->sadb_ext_type));
420 				return (EINVAL);
421 			}
422 
423 			if (sadb_sa->sadb_sa_auth > SADB_AALG_MAX) {
424 				DPRINTF(("pfkeyv2_parsemessage: unknown "
425 				    "authentication algorithm %d in SA "
426 				    "extension header %d\n",
427 				    sadb_sa->sadb_sa_auth,
428 				    sadb_ext->sadb_ext_type));
429 				return (EINVAL);
430 			}
431 
432 			if (sadb_sa->sadb_sa_replay > 64) {
433 				DPRINTF(("pfkeyv2_parsemessage: unsupported "
434 				    "replay window size %d in SA extension "
435 				    "header %d\n", sadb_sa->sadb_sa_replay,
436 				    sadb_ext->sadb_ext_type));
437 				return (EINVAL);
438 			}
439 		}
440 		break;
441 		case SADB_X_EXT_PROTOCOL:
442 		case SADB_X_EXT_FLOW_TYPE:
443 			if (i != sizeof(struct sadb_protocol)) {
444 				DPRINTF(("pfkeyv2_parsemessage: bad "
445 				    "PROTOCOL/FLOW header length in extension "
446 				    "header %d\n", sadb_ext->sadb_ext_type));
447 				return (EINVAL);
448 			}
449 			break;
450 		case SADB_X_EXT_POLICY:
451 			if (i != sizeof(struct sadb_x_policy)) {
452 				DPRINTF(("pfkeyv2_parsemessage: bad POLICY "
453 				    "header length\n"));
454 				return (EINVAL);
455 			}
456 			break;
457 		case SADB_EXT_LIFETIME_CURRENT:
458 		case SADB_EXT_LIFETIME_HARD:
459 		case SADB_EXT_LIFETIME_SOFT:
460 		case SADB_X_EXT_LIFETIME_LASTUSE:
461 			if (i != sizeof(struct sadb_lifetime)) {
462 				DPRINTF(("pfkeyv2_parsemessage: bad header "
463 				    "length for LIFETIME extension header "
464 				    "%d\n", sadb_ext->sadb_ext_type));
465 				return (EINVAL);
466 			}
467 			break;
468 		case SADB_EXT_ADDRESS_SRC:
469 		case SADB_EXT_ADDRESS_DST:
470 		case SADB_X_EXT_SRC_MASK:
471 		case SADB_X_EXT_DST_MASK:
472 		case SADB_X_EXT_SRC_FLOW:
473 		case SADB_X_EXT_DST_FLOW:
474 		case SADB_X_EXT_DST2:
475 		case SADB_EXT_ADDRESS_PROXY:
476 		{
477 			struct sadb_address *sadb_address =
478 			    (struct sadb_address *)p;
479 			struct sockaddr *sa = (struct sockaddr *)(p +
480 			    sizeof(struct sadb_address));
481 
482 			if (i < sizeof(struct sadb_address) +
483 			    sizeof(struct sockaddr)) {
484 				DPRINTF(("pfkeyv2_parsemessage: bad ADDRESS "
485 				    "extension header %d length\n",
486 				    sadb_ext->sadb_ext_type));
487 				return (EINVAL);
488 			}
489 
490 			if (sadb_address->sadb_address_reserved) {
491 				DPRINTF(("pfkeyv2_parsemessage: ADDRESS "
492 				    "extension header %d reserved field set\n",
493 				    sadb_ext->sadb_ext_type));
494 				return (EINVAL);
495 			}
496 			if (sa->sa_len &&
497 			    (i != sizeof(struct sadb_address) +
498 			    PADUP(sa->sa_len))) {
499 				DPRINTF(("pfkeyv2_parsemessage: bad sockaddr "
500 				    "length field in ADDRESS extension "
501 				    "header %d\n", sadb_ext->sadb_ext_type));
502 				return (EINVAL);
503 			}
504 
505 			switch (sa->sa_family) {
506 			case AF_INET:
507 				if (sizeof(struct sadb_address) +
508 				    PADUP(sizeof(struct sockaddr_in)) != i) {
509 					DPRINTF(("pfkeyv2_parsemessage: "
510 					    "invalid ADDRESS extension header "
511 					    "%d length\n",
512 					    sadb_ext->sadb_ext_type));
513 					return (EINVAL);
514 				}
515 
516 				if (sa->sa_len != sizeof(struct sockaddr_in)) {
517 					DPRINTF(("pfkeyv2_parsemessage: bad "
518 					    "sockaddr_in length in ADDRESS "
519 					    "extension header %d\n",
520 					    sadb_ext->sadb_ext_type));
521 					return (EINVAL);
522 				}
523 
524 				/* Only check the right pieces */
525 				switch (sadb_ext->sadb_ext_type)
526 				{
527 				case SADB_X_EXT_SRC_MASK:
528 				case SADB_X_EXT_DST_MASK:
529 				case SADB_X_EXT_SRC_FLOW:
530 				case SADB_X_EXT_DST_FLOW:
531 					break;
532 
533 				default:
534 					if (((struct sockaddr_in *)sa)->sin_port) {
535 						DPRINTF(("pfkeyv2_parsemessage"
536 						    ": port field set in "
537 						    "sockaddr_in of ADDRESS "
538 						    "extension header %d\n",
539 						    sadb_ext->sadb_ext_type));
540 						return (EINVAL);
541 					}
542 					break;
543 				}
544 
545 				{
546 					char zero[sizeof(((struct sockaddr_in *)sa)->sin_zero)];
547 					bzero(zero, sizeof(zero));
548 
549 					if (bcmp(&((struct sockaddr_in *)sa)->sin_zero, zero, sizeof(zero))) {
550 						DPRINTF(("pfkeyv2_parsemessage"
551 						    ": reserved sockaddr_in "
552 						    "field non-zero'ed in "
553 						    "ADDRESS extension header "
554 						    "%d\n",
555 						    sadb_ext->sadb_ext_type));
556 						return (EINVAL);
557 					}
558 				}
559 				break;
560 #ifdef INET6
561 			case AF_INET6:
562 				if (i != sizeof(struct sadb_address) +
563 				    PADUP(sizeof(struct sockaddr_in6))) {
564 					DPRINTF(("pfkeyv2_parsemessage: "
565 					    "invalid sockaddr_in6 length in "
566 					    "ADDRESS extension header %d\n",
567 					    sadb_ext->sadb_ext_type));
568 					return (EINVAL);
569 				}
570 
571 				if (sa->sa_len !=
572 				    sizeof(struct sockaddr_in6)) {
573 					DPRINTF(("pfkeyv2_parsemessage: bad "
574 					    "sockaddr_in6 length in ADDRESS "
575 					    "extension header %d\n",
576 					    sadb_ext->sadb_ext_type));
577 					return (EINVAL);
578 				}
579 
580 				if (((struct sockaddr_in6 *)sa)->sin6_flowinfo) {
581 					DPRINTF(("pfkeyv2_parsemessage: "
582 					    "flowinfo field set in "
583 					    "sockaddr_in6 of ADDRESS "
584 					    "extension header %d\n",
585 					    sadb_ext->sadb_ext_type));
586 					return (EINVAL);
587 				}
588 
589 				/* Only check the right pieces */
590 				switch (sadb_ext->sadb_ext_type)
591 				{
592 				case SADB_X_EXT_SRC_MASK:
593 				case SADB_X_EXT_DST_MASK:
594 				case SADB_X_EXT_SRC_FLOW:
595 				case SADB_X_EXT_DST_FLOW:
596 					break;
597 
598 				default:
599 					if (((struct sockaddr_in6 *)sa)->sin6_port) {
600 						DPRINTF(("pfkeyv2_parsemessage"
601 						    ": port field set in "
602 						    "sockaddr_in6 of ADDRESS "
603 						    "extension header %d\n",
604 						    sadb_ext->sadb_ext_type));
605 						return (EINVAL);
606 					}
607 					break;
608 				}
609 				break;
610 #endif /* INET6 */
611 			default:
612 				if (sadb_msg->sadb_msg_satype ==
613 				    SADB_X_SATYPE_TCPSIGNATURE &&
614 				    sa->sa_family == 0)
615 					break;
616 				DPRINTF(("pfkeyv2_parsemessage: unknown "
617 				    "address family %d in ADDRESS extension "
618 				    "header %d\n",
619 				    sa->sa_family, sadb_ext->sadb_ext_type));
620 				return (EINVAL);
621 			}
622 		}
623 		break;
624 		case SADB_EXT_KEY_AUTH:
625 		case SADB_EXT_KEY_ENCRYPT:
626 		{
627 			struct sadb_key *sadb_key = (struct sadb_key *)p;
628 
629 			if (i < sizeof(struct sadb_key)) {
630 				DPRINTF(("pfkeyv2_parsemessage: bad header "
631 				    "length in KEY extension header %d\n",
632 				    sadb_ext->sadb_ext_type));
633 				return (EINVAL);
634 			}
635 
636 			if (!sadb_key->sadb_key_bits) {
637 				DPRINTF(("pfkeyv2_parsemessage: key length "
638 				    "unset in KEY extension header %d\n",
639 				    sadb_ext->sadb_ext_type));
640 				return (EINVAL);
641 			}
642 
643 			if (((sadb_key->sadb_key_bits + 63) / 64) * sizeof(uint64_t) != i - sizeof(struct sadb_key)) {
644 				DPRINTF(("pfkeyv2_parsemessage: invalid key "
645 				    "length in KEY extension header %d\n",
646 				    sadb_ext->sadb_ext_type));
647 				return (EINVAL);
648 			}
649 
650 			if (sadb_key->sadb_key_reserved) {
651 				DPRINTF(("pfkeyv2_parsemessage: reserved field"
652 				    " set in KEY extension header %d\n",
653 				    sadb_ext->sadb_ext_type));
654 				return (EINVAL);
655 			}
656 		}
657 		break;
658 		case SADB_X_EXT_LOCAL_AUTH:
659 		case SADB_X_EXT_REMOTE_AUTH:
660 		{
661 			struct sadb_x_cred *sadb_cred =
662 			    (struct sadb_x_cred *)p;
663 
664 			if (i < sizeof(struct sadb_x_cred)) {
665 				DPRINTF(("pfkeyv2_parsemessage: bad header "
666 				    "length for AUTH extension header %d\n",
667 				    sadb_ext->sadb_ext_type));
668 				return (EINVAL);
669 			}
670 
671 			if (sadb_cred->sadb_x_cred_type > SADB_X_AUTHTYPE_MAX) {
672 				DPRINTF(("pfkeyv2_parsemessage: unknown auth "
673 				    "type %d in AUTH extension header %d\n",
674 				    sadb_cred->sadb_x_cred_type,
675 				    sadb_ext->sadb_ext_type));
676 				return (EINVAL);
677 			}
678 
679 			if (sadb_cred->sadb_x_cred_reserved) {
680 				DPRINTF(("pfkeyv2_parsemessage: reserved field"
681 				    " set in AUTH extension header %d\n",
682 				    sadb_ext->sadb_ext_type));
683 				return (EINVAL);
684 			}
685 		}
686 		break;
687 		case SADB_X_EXT_LOCAL_CREDENTIALS:
688 		case SADB_X_EXT_REMOTE_CREDENTIALS:
689 		{
690 			struct sadb_x_cred *sadb_cred =
691 			    (struct sadb_x_cred *)p;
692 
693 			if (i < sizeof(struct sadb_x_cred)) {
694 				DPRINTF(("pfkeyv2_parsemessage: bad header "
695 				    "length of CREDENTIALS extension header "
696 				    "%d\n", sadb_ext->sadb_ext_type));
697 				return (EINVAL);
698 			}
699 
700 			if (sadb_cred->sadb_x_cred_type > SADB_X_CREDTYPE_MAX) {
701 				DPRINTF(("pfkeyv2_parsemessage: unknown "
702 				    "credential type %d in CREDENTIALS "
703 				    "extension header %d\n",
704 				    sadb_cred->sadb_x_cred_type,
705 				    sadb_ext->sadb_ext_type));
706 				return (EINVAL);
707 			}
708 
709 			if (sadb_cred->sadb_x_cred_reserved) {
710 				DPRINTF(("pfkeyv2_parsemessage: reserved "
711 				    "field set in CREDENTIALS extension "
712 				    "header %d\n", sadb_ext->sadb_ext_type));
713 				return (EINVAL);
714 			}
715 		}
716 		break;
717 		case SADB_EXT_IDENTITY_SRC:
718 		case SADB_EXT_IDENTITY_DST:
719 		{
720 			struct sadb_ident *sadb_ident = (struct sadb_ident *)p;
721 
722 			if (i < sizeof(struct sadb_ident)) {
723 				DPRINTF(("pfkeyv2_parsemessage: bad header "
724 				    "length of IDENTITY extension header %d\n",
725 				    sadb_ext->sadb_ext_type));
726 				return (EINVAL);
727 			}
728 
729 			if (sadb_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) {
730 				DPRINTF(("pfkeyv2_parsemessage: unknown "
731 				    "identity type %d in IDENTITY extension "
732 				    "header %d\n",
733 				    sadb_ident->sadb_ident_type,
734 				    sadb_ext->sadb_ext_type));
735 				return (EINVAL);
736 			}
737 
738 			if (sadb_ident->sadb_ident_reserved) {
739 				DPRINTF(("pfkeyv2_parsemessage: reserved "
740 				    "field set in IDENTITY extension header "
741 				    "%d\n", sadb_ext->sadb_ext_type));
742 				return (EINVAL);
743 			}
744 
745 			if (i > sizeof(struct sadb_ident)) {
746 				char *c =
747 				    (char *)(p + sizeof(struct sadb_ident));
748 				int j;
749 
750 				if (*(char *)(p + i - 1)) {
751 					DPRINTF(("pfkeyv2_parsemessage: non "
752 					    "NUL-terminated identity in "
753 					    "IDENTITY extension header %d\n",
754 					    sadb_ext->sadb_ext_type));
755 					return (EINVAL);
756 				}
757 
758 				j = PADUP(strlen(c) + 1) +
759 				    sizeof(struct sadb_ident);
760 
761 				if (i != j) {
762 					DPRINTF(("pfkeyv2_parsemessage: actual"
763 					    " identity length does not match "
764 					    "expected length in identity "
765 					    "extension header %d\n",
766 					    sadb_ext->sadb_ext_type));
767 					return (EINVAL);
768 				}
769 			}
770 		}
771 		break;
772 		case SADB_EXT_SENSITIVITY:
773 		{
774 			struct sadb_sens *sadb_sens = (struct sadb_sens *)p;
775 
776 			if (i < sizeof(struct sadb_sens)) {
777 				DPRINTF(("pfkeyv2_parsemessage: bad header "
778 				    "length for SENSITIVITY extension "
779 				    "header\n"));
780 				return (EINVAL);
781 			}
782 
783 			if (i != (sadb_sens->sadb_sens_sens_len +
784 			    sadb_sens->sadb_sens_integ_len) *
785 			    sizeof(uint64_t) +
786 			    sizeof(struct sadb_sens)) {
787 				DPRINTF(("pfkeyv2_parsemessage: bad payload "
788 				    "length for SENSITIVITY extension "
789 				    "header\n"));
790 				return (EINVAL);
791 			}
792 		}
793 		break;
794 		case SADB_EXT_PROPOSAL:
795 		{
796 			struct sadb_prop *sadb_prop = (struct sadb_prop *)p;
797 
798 			if (i < sizeof(struct sadb_prop)) {
799 				DPRINTF(("pfkeyv2_parsemessage: bad PROPOSAL "
800 				    "header length\n"));
801 				return (EINVAL);
802 			}
803 
804 			if (sadb_prop->sadb_prop_reserved) {
805 				DPRINTF(("pfkeyv2_parsemessage: reserved field"
806 				    "set in PROPOSAL extension header\n"));
807 				return (EINVAL);
808 			}
809 
810 			if ((i - sizeof(struct sadb_prop)) %
811 			    sizeof(struct sadb_comb)) {
812 				DPRINTF(("pfkeyv2_parsemessage: bad proposal "
813 				    "length\n"));
814 				return (EINVAL);
815 			}
816 
817 			{
818 				struct sadb_comb *sadb_comb =
819 				    (struct sadb_comb *)(p +
820 					sizeof(struct sadb_prop));
821 				int j;
822 
823 				for (j = 0;
824 				    j < (i - sizeof(struct sadb_prop))/
825 				    sizeof(struct sadb_comb);
826 				    j++) {
827 					if (sadb_comb->sadb_comb_auth >
828 					    SADB_AALG_MAX) {
829 						DPRINTF(("pfkeyv2_parsemessage"
830 						    ": unknown authentication "
831 						    "algorithm %d in "
832 						    "PROPOSAL\n",
833 						    sadb_comb->sadb_comb_auth));
834 						return (EINVAL);
835 					}
836 
837 					if (sadb_comb->sadb_comb_encrypt >
838 					    SADB_EALG_MAX) {
839 						DPRINTF(("pfkeyv2_parsemessage"
840 						    ": unknown encryption "
841 						    "algorithm %d in "
842 						    "PROPOSAL\n",
843 						    sadb_comb->sadb_comb_encrypt));
844 						return (EINVAL);
845 					}
846 
847 					if (sadb_comb->sadb_comb_reserved) {
848 						DPRINTF(("pfkeyv2_parsemessage"
849 						    ": reserved field set in "
850 						    "COMB header\n"));
851 						return (EINVAL);
852 					}
853 				}
854 			}
855 		}
856 		break;
857 		case SADB_EXT_SUPPORTED_AUTH:
858 		case SADB_EXT_SUPPORTED_ENCRYPT:
859 		case SADB_X_EXT_SUPPORTED_COMP:
860 		{
861 			struct sadb_supported *sadb_supported =
862 			    (struct sadb_supported *)p;
863 			int j;
864 
865 			if (i < sizeof(struct sadb_supported)) {
866 				DPRINTF(("pfkeyv2_parsemessage: bad header "
867 				    "length for SUPPORTED extension header "
868 				    "%d\n", sadb_ext->sadb_ext_type));
869 				return (EINVAL);
870 			}
871 
872 			if (sadb_supported->sadb_supported_reserved) {
873 				DPRINTF(("pfkeyv2_parsemessage: reserved "
874 				    "field set in SUPPORTED extension "
875 				    "header %d\n", sadb_ext->sadb_ext_type));
876 				return (EINVAL);
877 			}
878 
879 			{
880 				struct sadb_alg *sadb_alg =
881 				    (struct sadb_alg *)(p +
882 					sizeof(struct sadb_supported));
883 				int max_alg;
884 
885 				max_alg = sadb_ext->sadb_ext_type ==
886 				    SADB_EXT_SUPPORTED_AUTH ?
887 				    SADB_AALG_MAX : SADB_EXT_SUPPORTED_ENCRYPT ?
888 				    SADB_EALG_MAX : SADB_X_CALG_MAX;
889 
890 				for (j = 0;
891 				    j < sadb_supported->sadb_supported_len - 1;
892 				    j++) {
893 					if (sadb_alg->sadb_alg_id > max_alg) {
894 						DPRINTF(("pfkeyv2_parsemessage"
895 						    ": unknown algorithm %d "
896 						    "in SUPPORTED extension "
897 						    "header %d\n",
898 						    sadb_alg->sadb_alg_id,
899 						    sadb_ext->sadb_ext_type));
900 						return (EINVAL);
901 					}
902 
903 					if (sadb_alg->sadb_alg_reserved) {
904 						DPRINTF(("pfkeyv2_parsemessage"
905 						    ": reserved field set in "
906 						    "supported algorithms "
907 						    "header inside SUPPORTED "
908 						    "extension header %d\n",
909 						    sadb_ext->sadb_ext_type));
910 						return (EINVAL);
911 					}
912 
913 					sadb_alg++;
914 				}
915 			}
916 		}
917 		break;
918 		case SADB_EXT_SPIRANGE:
919 		{
920 			struct sadb_spirange *sadb_spirange =
921 			    (struct sadb_spirange *)p;
922 
923 			if (i != sizeof(struct sadb_spirange)) {
924 				DPRINTF(("pfkeyv2_parsemessage: bad header "
925 				    "length of SPIRANGE extension header\n"));
926 				return (EINVAL);
927 			}
928 
929 			if (sadb_spirange->sadb_spirange_min >
930 			    sadb_spirange->sadb_spirange_max) {
931 				DPRINTF(("pfkeyv2_parsemessage: bad SPI "
932 				    "range\n"));
933 				return (EINVAL);
934 			}
935 		}
936 		break;
937 		case SADB_X_EXT_UDPENCAP:
938 			if (i != sizeof(struct sadb_x_udpencap)) {
939 				DPRINTF(("pfkeyv2_parsemessage: bad UDPENCAP "
940 				    "header length\n"));
941 				return (EINVAL);
942 			}
943 			break;
944 #if NPF > 0
945 		case SADB_X_EXT_TAG:
946 			if (i < sizeof(struct sadb_x_tag)) {
947 				DPRINTF(("pfkeyv2_parsemessage: "
948 				    "TAG extension header too small"));
949 				return (EINVAL);
950 			}
951 			if (i > (sizeof(struct sadb_x_tag) +
952 			    PF_TAG_NAME_SIZE)) {
953 				DPRINTF(("pfkeyv2_parsemessage: "
954 				    "TAG extension header too long"));
955 				return (EINVAL);
956 			}
957 			break;
958 		case SADB_X_EXT_TAP:
959 			if (i < sizeof(struct sadb_x_tap)) {
960 				DPRINTF(("pfkeyv2_parsemessage: "
961 				    "TAP extension header too small"));
962 				return (EINVAL);
963 			}
964 			if (i > sizeof(struct sadb_x_tap)) {
965 				DPRINTF(("pfkeyv2_parsemessage: "
966 				    "TAP extension header too long"));
967 				return (EINVAL);
968 			}
969 			break;
970 #endif
971 		default:
972 			DPRINTF(("pfkeyv2_parsemessage: unknown extension "
973 			    "header type %d\n",
974 			    sadb_ext->sadb_ext_type));
975 			return (EINVAL);
976 		}
977 
978 		headers[sadb_ext->sadb_ext_type] = p;
979 		p += i;
980 		left -= i;
981 	}
982 
983 	if (left) {
984 		DPRINTF(("pfkeyv2_parsemessage: message too long\n"));
985 		return (EINVAL);
986 	}
987 
988 	{
989 		uint64_t required;
990 
991 		required = sadb_exts_required_in[sadb_msg->sadb_msg_type];
992 
993 		if ((seen & required) != required) {
994 			DPRINTF(("pfkeyv2_parsemessage: required fields "
995 			    "missing\n"));
996 			return (EINVAL);
997 		}
998 	}
999 
1000 	switch (((struct sadb_msg *)headers[0])->sadb_msg_type) {
1001 	case SADB_UPDATE:
1002 		if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state !=
1003 		    SADB_SASTATE_MATURE) {
1004 			DPRINTF(("pfkeyv2_parsemessage: updating non-mature "
1005 			    "SA prohibited\n"));
1006 			return (EINVAL);
1007 		}
1008 		break;
1009 	case SADB_ADD:
1010 		if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state !=
1011 		    SADB_SASTATE_MATURE) {
1012 			DPRINTF(("pfkeyv2_parsemessage: adding non-mature "
1013 			    "SA prohibited\n"));
1014 			return (EINVAL);
1015 		}
1016 		break;
1017 	}
1018 
1019 	return (0);
1020 }
1021