xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_auth.c (revision af5f29dd)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
5f4b3ec61Sdh  *
6786c7074Sjojemann  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
7381a2a9aSdr  * Use is subject to license terms.
8381a2a9aSdr  */
9381a2a9aSdr 
107c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL)
117c478bd9Sstevel@tonic-gate # undef KERNEL
127c478bd9Sstevel@tonic-gate # undef _KERNEL
137c478bd9Sstevel@tonic-gate # define        KERNEL	1
147c478bd9Sstevel@tonic-gate # define        _KERNEL	1
157c478bd9Sstevel@tonic-gate #endif
167c478bd9Sstevel@tonic-gate #include <sys/errno.h>
177c478bd9Sstevel@tonic-gate #include <sys/types.h>
187c478bd9Sstevel@tonic-gate #include <sys/param.h>
197c478bd9Sstevel@tonic-gate #include <sys/time.h>
207c478bd9Sstevel@tonic-gate #include <sys/file.h>
217c478bd9Sstevel@tonic-gate #if !defined(_KERNEL)
227c478bd9Sstevel@tonic-gate # include <stdio.h>
237c478bd9Sstevel@tonic-gate # include <stdlib.h>
247c478bd9Sstevel@tonic-gate # include <string.h>
257c478bd9Sstevel@tonic-gate # define _KERNEL
267c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__
277c478bd9Sstevel@tonic-gate struct file;
287c478bd9Sstevel@tonic-gate # endif
297c478bd9Sstevel@tonic-gate # include <sys/uio.h>
307c478bd9Sstevel@tonic-gate # undef _KERNEL
317c478bd9Sstevel@tonic-gate #endif
327c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
337c478bd9Sstevel@tonic-gate # include <sys/filio.h>
347c478bd9Sstevel@tonic-gate # include <sys/fcntl.h>
357c478bd9Sstevel@tonic-gate #else
367c478bd9Sstevel@tonic-gate # include <sys/ioctl.h>
377c478bd9Sstevel@tonic-gate #endif
38ab25eeb5Syz #if !defined(linux)
39ab25eeb5Syz # include <sys/protosw.h>
40ab25eeb5Syz #endif
417c478bd9Sstevel@tonic-gate #include <sys/socket.h>
427c478bd9Sstevel@tonic-gate #if defined(_KERNEL)
437c478bd9Sstevel@tonic-gate # include <sys/systm.h>
44ab25eeb5Syz # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux)
457c478bd9Sstevel@tonic-gate #  include <sys/mbuf.h>
467c478bd9Sstevel@tonic-gate # endif
477c478bd9Sstevel@tonic-gate #endif
487c478bd9Sstevel@tonic-gate #if defined(__SVR4) || defined(__svr4__)
497c478bd9Sstevel@tonic-gate # include <sys/filio.h>
507c478bd9Sstevel@tonic-gate # include <sys/byteorder.h>
517c478bd9Sstevel@tonic-gate # ifdef _KERNEL
527c478bd9Sstevel@tonic-gate #  include <sys/dditypes.h>
537c478bd9Sstevel@tonic-gate # endif
547c478bd9Sstevel@tonic-gate # include <sys/stream.h>
557c478bd9Sstevel@tonic-gate # include <sys/kmem.h>
56381a2a9aSdr # include <sys/neti.h>
577c478bd9Sstevel@tonic-gate #endif
587c478bd9Sstevel@tonic-gate #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000)
597c478bd9Sstevel@tonic-gate # include <sys/queue.h>
607c478bd9Sstevel@tonic-gate #endif
617c478bd9Sstevel@tonic-gate #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
627c478bd9Sstevel@tonic-gate # include <machine/cpu.h>
637c478bd9Sstevel@tonic-gate #endif
647c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
657c478bd9Sstevel@tonic-gate # include <sys/proc.h>
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate #include <net/if.h>
687c478bd9Sstevel@tonic-gate #ifdef sun
697c478bd9Sstevel@tonic-gate # include <net/af.h>
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate #include <net/route.h>
727c478bd9Sstevel@tonic-gate #include <netinet/in.h>
737c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
747c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
75ab25eeb5Syz #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi)
767c478bd9Sstevel@tonic-gate # define	KERNEL
777c478bd9Sstevel@tonic-gate # define	_KERNEL
787c478bd9Sstevel@tonic-gate # define	NOT_KERNEL
797c478bd9Sstevel@tonic-gate #endif
80ab25eeb5Syz #if !defined(linux)
81ab25eeb5Syz # include <netinet/ip_var.h>
82ab25eeb5Syz #endif
837c478bd9Sstevel@tonic-gate #ifdef	NOT_KERNEL
847c478bd9Sstevel@tonic-gate # undef	_KERNEL
857c478bd9Sstevel@tonic-gate # undef	KERNEL
867c478bd9Sstevel@tonic-gate #endif
877c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
88ab25eeb5Syz #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */
897c478bd9Sstevel@tonic-gate extern struct ifqueue   ipintrq;		/* ip packet input queue */
907c478bd9Sstevel@tonic-gate #else
91ab25eeb5Syz # if !defined(__hpux) && !defined(linux)
927c478bd9Sstevel@tonic-gate #  if __FreeBSD_version >= 300000
937c478bd9Sstevel@tonic-gate #   include <net/if_var.h>
947c478bd9Sstevel@tonic-gate #   if __FreeBSD_version >= 500042
957c478bd9Sstevel@tonic-gate #    define IF_QFULL _IF_QFULL
967c478bd9Sstevel@tonic-gate #    define IF_DROP _IF_DROP
977c478bd9Sstevel@tonic-gate #   endif /* __FreeBSD_version >= 500042 */
987c478bd9Sstevel@tonic-gate #  endif
997c478bd9Sstevel@tonic-gate #  include <netinet/in_var.h>
1007c478bd9Sstevel@tonic-gate #  include <netinet/tcp_fsm.h>
1017c478bd9Sstevel@tonic-gate # endif
1027c478bd9Sstevel@tonic-gate #endif
1037c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
1047c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
1057c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h"
106ab25eeb5Syz #include <netinet/tcpip.h>
107f4b3ec61Sdh #include "netinet/ipf_stack.h"
1087c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h"
1097c478bd9Sstevel@tonic-gate #include "netinet/ip_auth.h"
110ab25eeb5Syz #if !defined(MENTAT) && !defined(linux)
1117c478bd9Sstevel@tonic-gate # include <net/netisr.h>
1127c478bd9Sstevel@tonic-gate # ifdef __FreeBSD__
1137c478bd9Sstevel@tonic-gate #  include <machine/cpufunc.h>
1147c478bd9Sstevel@tonic-gate # endif
1157c478bd9Sstevel@tonic-gate #endif
1167c478bd9Sstevel@tonic-gate #if (__FreeBSD_version >= 300000)
1177c478bd9Sstevel@tonic-gate # include <sys/malloc.h>
1187c478bd9Sstevel@tonic-gate # if defined(_KERNEL) && !defined(IPFILTER_LKM)
1197c478bd9Sstevel@tonic-gate #  include <sys/libkern.h>
1207c478bd9Sstevel@tonic-gate #  include <sys/systm.h>
1217c478bd9Sstevel@tonic-gate # endif
1227c478bd9Sstevel@tonic-gate #endif
123ab25eeb5Syz /* END OF INCLUDES */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate #if !defined(lint)
126ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $";
1277c478bd9Sstevel@tonic-gate #endif
1287c478bd9Sstevel@tonic-gate 
129f4b3ec61Sdh void fr_authderef __P((frauthent_t **));
130f4b3ec61Sdh int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 
fr_authinit(ifs)133f4b3ec61Sdh int fr_authinit(ifs)
134f4b3ec61Sdh ipf_stack_t *ifs;
1357c478bd9Sstevel@tonic-gate {
136f4b3ec61Sdh 	KMALLOCS(ifs->ifs_fr_auth, frauth_t *,
137f4b3ec61Sdh 		 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth));
138f4b3ec61Sdh 	if (ifs->ifs_fr_auth != NULL)
139f4b3ec61Sdh 		bzero((char *)ifs->ifs_fr_auth,
140f4b3ec61Sdh 		      ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth));
1417c478bd9Sstevel@tonic-gate 	else
1427c478bd9Sstevel@tonic-gate 		return -1;
1437c478bd9Sstevel@tonic-gate 
144f4b3ec61Sdh 	KMALLOCS(ifs->ifs_fr_authpkts, mb_t **,
145f4b3ec61Sdh 		 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts));
146f4b3ec61Sdh 	if (ifs->ifs_fr_authpkts != NULL)
147f4b3ec61Sdh 		bzero((char *)ifs->ifs_fr_authpkts,
148f4b3ec61Sdh 		      ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts));
1497c478bd9Sstevel@tonic-gate 	else
150ab25eeb5Syz 		return -2;
1517c478bd9Sstevel@tonic-gate 
152f4b3ec61Sdh 	MUTEX_INIT(&ifs->ifs_ipf_authmx, "ipf auth log mutex");
153f4b3ec61Sdh 	RWLOCK_INIT(&ifs->ifs_ipf_auth, "ipf IP User-Auth rwlock");
154*af5f29ddSToomas Soome #if defined(SOLARIS) && defined(_KERNEL)
155f4b3ec61Sdh 	cv_init(&ifs->ifs_ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL);
1567c478bd9Sstevel@tonic-gate #endif
157ab25eeb5Syz #if defined(linux) && defined(_KERNEL)
158ab25eeb5Syz 	init_waitqueue_head(&fr_authnext_linux);
159ab25eeb5Syz #endif
1607c478bd9Sstevel@tonic-gate 
161f4b3ec61Sdh 	ifs->ifs_fr_auth_init = 1;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	return 0;
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * Check if a packet has authorization.  If the packet is found to match an
1697c478bd9Sstevel@tonic-gate  * authorization result and that would result in a feedback loop (i.e. it
1707c478bd9Sstevel@tonic-gate  * will end up returning FR_AUTH) then return FR_BLOCK instead.
1717c478bd9Sstevel@tonic-gate  */
fr_checkauth(fin,passp)1727c478bd9Sstevel@tonic-gate frentry_t *fr_checkauth(fin, passp)
1737c478bd9Sstevel@tonic-gate fr_info_t *fin;
1747c478bd9Sstevel@tonic-gate u_32_t *passp;
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate 	frentry_t *fr;
1777c478bd9Sstevel@tonic-gate 	frauth_t *fra;
1787c478bd9Sstevel@tonic-gate 	u_32_t pass;
1797c478bd9Sstevel@tonic-gate 	u_short id;
1807c478bd9Sstevel@tonic-gate 	ip_t *ip;
1817c478bd9Sstevel@tonic-gate 	int i;
182f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
1837c478bd9Sstevel@tonic-gate 
184f4b3ec61Sdh 	if (ifs->ifs_fr_auth_lock || !ifs->ifs_fr_authused)
1857c478bd9Sstevel@tonic-gate 		return NULL;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	ip = fin->fin_ip;
1887c478bd9Sstevel@tonic-gate 	id = ip->ip_id;
1897c478bd9Sstevel@tonic-gate 
190f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_auth);
191f4b3ec61Sdh 	for (i = ifs->ifs_fr_authstart; i != ifs->ifs_fr_authend; ) {
1927c478bd9Sstevel@tonic-gate 		/*
1937c478bd9Sstevel@tonic-gate 		 * index becomes -2 only after an SIOCAUTHW.  Check this in
1947c478bd9Sstevel@tonic-gate 		 * case the same packet gets sent again and it hasn't yet been
1957c478bd9Sstevel@tonic-gate 		 * auth'd.
1967c478bd9Sstevel@tonic-gate 		 */
197f4b3ec61Sdh 		fra = ifs->ifs_fr_auth + i;
1987c478bd9Sstevel@tonic-gate 		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
1997c478bd9Sstevel@tonic-gate 		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
2007c478bd9Sstevel@tonic-gate 			/*
2017c478bd9Sstevel@tonic-gate 			 * Avoid feedback loop.
2027c478bd9Sstevel@tonic-gate 			 */
2037c478bd9Sstevel@tonic-gate 			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass)))
2047c478bd9Sstevel@tonic-gate 				pass = FR_BLOCK;
2057c478bd9Sstevel@tonic-gate 			/*
2067c478bd9Sstevel@tonic-gate 			 * Create a dummy rule for the stateful checking to
2077c478bd9Sstevel@tonic-gate 			 * use and return.  Zero out any values we don't
2087c478bd9Sstevel@tonic-gate 			 * trust from userland!
2097c478bd9Sstevel@tonic-gate 			 */
2107c478bd9Sstevel@tonic-gate 			if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
2117c478bd9Sstevel@tonic-gate 			     (fin->fin_flx & FI_FRAG))) {
2127c478bd9Sstevel@tonic-gate 				KMALLOC(fr, frentry_t *);
2137c478bd9Sstevel@tonic-gate 				if (fr) {
2147c478bd9Sstevel@tonic-gate 					bcopy((char *)fra->fra_info.fin_fr,
2157c478bd9Sstevel@tonic-gate 					      (char *)fr, sizeof(*fr));
2167c478bd9Sstevel@tonic-gate 					fr->fr_grp = NULL;
2177c478bd9Sstevel@tonic-gate 					fr->fr_ifa = fin->fin_ifp;
2187c478bd9Sstevel@tonic-gate 					fr->fr_func = NULL;
2197c478bd9Sstevel@tonic-gate 					fr->fr_ref = 1;
2207c478bd9Sstevel@tonic-gate 					fr->fr_flags = pass;
2217c478bd9Sstevel@tonic-gate 					fr->fr_ifas[1] = NULL;
2227c478bd9Sstevel@tonic-gate 					fr->fr_ifas[2] = NULL;
2237c478bd9Sstevel@tonic-gate 					fr->fr_ifas[3] = NULL;
2247c478bd9Sstevel@tonic-gate 				}
2257c478bd9Sstevel@tonic-gate 			} else
2267c478bd9Sstevel@tonic-gate 				fr = fra->fra_info.fin_fr;
2277c478bd9Sstevel@tonic-gate 			fin->fin_fr = fr;
228f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
229f4b3ec61Sdh 			WRITE_ENTER(&ifs->ifs_ipf_auth);
2307c478bd9Sstevel@tonic-gate 			if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
231f4b3ec61Sdh 				fr->fr_next = ifs->ifs_fr_authlist;
232f4b3ec61Sdh 				ifs->ifs_fr_authlist = fr;
2337c478bd9Sstevel@tonic-gate 			}
234f4b3ec61Sdh 			ifs->ifs_fr_authstats.fas_hits++;
2357c478bd9Sstevel@tonic-gate 			fra->fra_index = -1;
236f4b3ec61Sdh 			ifs->ifs_fr_authused--;
237f4b3ec61Sdh 			if (i == ifs->ifs_fr_authstart) {
2387c478bd9Sstevel@tonic-gate 				while (fra->fra_index == -1) {
2397c478bd9Sstevel@tonic-gate 					i++;
2407c478bd9Sstevel@tonic-gate 					fra++;
241f4b3ec61Sdh 					if (i == ifs->ifs_fr_authsize) {
2427c478bd9Sstevel@tonic-gate 						i = 0;
243f4b3ec61Sdh 						fra = ifs->ifs_fr_auth;
2447c478bd9Sstevel@tonic-gate 					}
245f4b3ec61Sdh 					ifs->ifs_fr_authstart = i;
246f4b3ec61Sdh 					if (i == ifs->ifs_fr_authend)
2477c478bd9Sstevel@tonic-gate 						break;
2487c478bd9Sstevel@tonic-gate 				}
249f4b3ec61Sdh 				if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) {
250f4b3ec61Sdh 					ifs->ifs_fr_authnext = 0;
251f4b3ec61Sdh 					ifs->ifs_fr_authstart = 0;
252f4b3ec61Sdh 					ifs->ifs_fr_authend = 0;
2537c478bd9Sstevel@tonic-gate 				}
2547c478bd9Sstevel@tonic-gate 			}
255f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
2567c478bd9Sstevel@tonic-gate 			if (passp != NULL)
2577c478bd9Sstevel@tonic-gate 				*passp = pass;
258f4b3ec61Sdh 			ATOMIC_INC64(ifs->ifs_fr_authstats.fas_hits);
2597c478bd9Sstevel@tonic-gate 			return fr;
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 		i++;
262f4b3ec61Sdh 		if (i == ifs->ifs_fr_authsize)
2637c478bd9Sstevel@tonic-gate 			i = 0;
2647c478bd9Sstevel@tonic-gate 	}
265f4b3ec61Sdh 	ifs->ifs_fr_authstats.fas_miss++;
266f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
267f4b3ec61Sdh 	ATOMIC_INC64(ifs->ifs_fr_authstats.fas_miss);
2687c478bd9Sstevel@tonic-gate 	return NULL;
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate  * Check if we have room in the auth array to hold details for another packet.
2747c478bd9Sstevel@tonic-gate  * If we do, store it and wake up any user programs which are waiting to
2757c478bd9Sstevel@tonic-gate  * hear about these events.
2767c478bd9Sstevel@tonic-gate  */
fr_newauth(m,fin)2777c478bd9Sstevel@tonic-gate int fr_newauth(m, fin)
2787c478bd9Sstevel@tonic-gate mb_t *m;
2797c478bd9Sstevel@tonic-gate fr_info_t *fin;
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && defined(MENTAT)
282ab25eeb5Syz 	qpktinfo_t *qpi = fin->fin_qpi;
2837c478bd9Sstevel@tonic-gate #endif
2847c478bd9Sstevel@tonic-gate 	frauth_t *fra;
2857c478bd9Sstevel@tonic-gate #if !defined(sparc) && !defined(m68k)
2867c478bd9Sstevel@tonic-gate 	ip_t *ip;
2877c478bd9Sstevel@tonic-gate #endif
2887c478bd9Sstevel@tonic-gate 	int i;
289f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
2907c478bd9Sstevel@tonic-gate 
291f4b3ec61Sdh 	if (ifs->ifs_fr_auth_lock)
2927c478bd9Sstevel@tonic-gate 		return 0;
2937c478bd9Sstevel@tonic-gate 
294f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_auth);
295f4b3ec61Sdh 	if (ifs->ifs_fr_authstart > ifs->ifs_fr_authend) {
296f4b3ec61Sdh 		ifs->ifs_fr_authstats.fas_nospace++;
297f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
2987c478bd9Sstevel@tonic-gate 		return 0;
2997c478bd9Sstevel@tonic-gate 	} else {
300f4b3ec61Sdh 		if (ifs->ifs_fr_authused == ifs->ifs_fr_authsize) {
301f4b3ec61Sdh 			ifs->ifs_fr_authstats.fas_nospace++;
302f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
3037c478bd9Sstevel@tonic-gate 			return 0;
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
307f4b3ec61Sdh 	ifs->ifs_fr_authstats.fas_added++;
308f4b3ec61Sdh 	ifs->ifs_fr_authused++;
309f4b3ec61Sdh 	i = ifs->ifs_fr_authend++;
310f4b3ec61Sdh 	if (ifs->ifs_fr_authend == ifs->ifs_fr_authsize)
311f4b3ec61Sdh 		ifs->ifs_fr_authend = 0;
312f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
3137c478bd9Sstevel@tonic-gate 
314f4b3ec61Sdh 	fra = ifs->ifs_fr_auth + i;
3157c478bd9Sstevel@tonic-gate 	fra->fra_index = i;
3167c478bd9Sstevel@tonic-gate 	fra->fra_pass = 0;
317f4b3ec61Sdh 	fra->fra_age = ifs->ifs_fr_defaultauthage;
3187c478bd9Sstevel@tonic-gate 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
3197c478bd9Sstevel@tonic-gate #if !defined(sparc) && !defined(m68k)
3207c478bd9Sstevel@tonic-gate 	/*
3217c478bd9Sstevel@tonic-gate 	 * No need to copyback here as we want to undo the changes, not keep
3227c478bd9Sstevel@tonic-gate 	 * them.
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	ip = fin->fin_ip;
3257c478bd9Sstevel@tonic-gate # if defined(MENTAT) && defined(_KERNEL)
3267c478bd9Sstevel@tonic-gate 	if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4))
3277c478bd9Sstevel@tonic-gate # endif
3287c478bd9Sstevel@tonic-gate 	{
3297c478bd9Sstevel@tonic-gate 		register u_short bo;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 		bo = ip->ip_len;
3327c478bd9Sstevel@tonic-gate 		ip->ip_len = htons(bo);
3337c478bd9Sstevel@tonic-gate 		bo = ip->ip_off;
3347c478bd9Sstevel@tonic-gate 		ip->ip_off = htons(bo);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate #endif
337*af5f29ddSToomas Soome #if defined(SOLARIS) && defined(_KERNEL)
338ab25eeb5Syz 	m->b_rptr -= qpi->qpi_off;
339f4b3ec61Sdh 	ifs->ifs_fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
340f4b3ec61Sdh 	cv_signal(&ifs->ifs_ipfauthwait);
3417c478bd9Sstevel@tonic-gate #else
3427c478bd9Sstevel@tonic-gate # if defined(BSD) && !defined(sparc) && (BSD >= 199306)
3437c478bd9Sstevel@tonic-gate 	if (!fin->fin_out) {
3447c478bd9Sstevel@tonic-gate 		ip->ip_len = htons(ip->ip_len);
3457c478bd9Sstevel@tonic-gate 		ip->ip_off = htons(ip->ip_off);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate # endif
348f4b3ec61Sdh 	ifs->ifs_fr_authpkts[i] = m;
349f4b3ec61Sdh 	WAKEUP(&ifs->ifs_fr_authnext, 0);
3507c478bd9Sstevel@tonic-gate #endif
3517c478bd9Sstevel@tonic-gate 	return 1;
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 
fr_auth_ioctl(data,cmd,mode,uid,ctx,ifs)355f4b3ec61Sdh int fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs)
3567c478bd9Sstevel@tonic-gate caddr_t data;
357ab25eeb5Syz ioctlcmd_t cmd;
358f4b3ec61Sdh int mode,uid;
359f4b3ec61Sdh void *ctx;
360f4b3ec61Sdh ipf_stack_t *ifs;
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	mb_t *m;
363ab25eeb5Syz #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \
364ab25eeb5Syz     (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000))
3657c478bd9Sstevel@tonic-gate 	struct ifqueue *ifq;
366ab25eeb5Syz 	SPL_INT(s);
3677c478bd9Sstevel@tonic-gate #endif
3687c478bd9Sstevel@tonic-gate 	frauth_t auth, *au = &auth, *fra;
3697c478bd9Sstevel@tonic-gate 	int i, error = 0, len;
3707c478bd9Sstevel@tonic-gate 	char *t;
3717ddc9b1aSDarren Reed 	net_handle_t net_data_p;
372381a2a9aSdr 	net_inject_t inj_data;
373381a2a9aSdr 	int ret;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	switch (cmd)
3767c478bd9Sstevel@tonic-gate 	{
377f4b3ec61Sdh 	case SIOCGENITER :
378f4b3ec61Sdh 	    {
379f4b3ec61Sdh 		ipftoken_t *token;
380f4b3ec61Sdh 		ipfgeniter_t iter;
381f4b3ec61Sdh 
382f4b3ec61Sdh 		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
383f4b3ec61Sdh 		if (error != 0)
384f4b3ec61Sdh 			break;
385f4b3ec61Sdh 
386f4b3ec61Sdh 		token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx, ifs);
387f4b3ec61Sdh 		if (token != NULL)
388f4b3ec61Sdh 			error = fr_authgeniter(token, &iter, ifs);
389f4b3ec61Sdh 		else
390f4b3ec61Sdh 			error = ESRCH;
391f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_tokens);
392f4b3ec61Sdh 
393f4b3ec61Sdh 		break;
394f4b3ec61Sdh 	    }
395f4b3ec61Sdh 
3967c478bd9Sstevel@tonic-gate 	case SIOCSTLCK :
3977c478bd9Sstevel@tonic-gate 		if (!(mode & FWRITE)) {
3987c478bd9Sstevel@tonic-gate 			error = EPERM;
3997c478bd9Sstevel@tonic-gate 			break;
4007c478bd9Sstevel@tonic-gate 		}
401bb1d9de5SJohn Ojemann 		error = fr_lock(data, &ifs->ifs_fr_auth_lock);
4027c478bd9Sstevel@tonic-gate 		break;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	case SIOCATHST:
405f4b3ec61Sdh 		ifs->ifs_fr_authstats.fas_faelist = ifs->ifs_fae_list;
406f4b3ec61Sdh 		error = fr_outobj(data, &ifs->ifs_fr_authstats,
407f4b3ec61Sdh 		    IPFOBJ_AUTHSTAT);
4087c478bd9Sstevel@tonic-gate 		break;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	case SIOCIPFFL:
4117c478bd9Sstevel@tonic-gate 		SPL_NET(s);
412f4b3ec61Sdh 		WRITE_ENTER(&ifs->ifs_ipf_auth);
413f4b3ec61Sdh 		i = fr_authflush(ifs);
414f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
4157c478bd9Sstevel@tonic-gate 		SPL_X(s);
4167c478bd9Sstevel@tonic-gate 		error = copyoutptr((char *)&i, data, sizeof(i));
4177c478bd9Sstevel@tonic-gate 		break;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	case SIOCAUTHW:
4207c478bd9Sstevel@tonic-gate fr_authioctlloop:
4217c478bd9Sstevel@tonic-gate 		error = fr_inobj(data, au, IPFOBJ_FRAUTH);
422f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_auth);
423f4b3ec61Sdh 		if ((ifs->ifs_fr_authnext != ifs->ifs_fr_authend) &&
424f4b3ec61Sdh 		    ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]) {
425f4b3ec61Sdh 			error = fr_outobj(data,
426f4b3ec61Sdh 					  &ifs->ifs_fr_auth[ifs->ifs_fr_authnext],
4277c478bd9Sstevel@tonic-gate 					  IPFOBJ_FRAUTH);
4287c478bd9Sstevel@tonic-gate 			if (auth.fra_len != 0 && auth.fra_buf != NULL) {
4297c478bd9Sstevel@tonic-gate 				/*
4307c478bd9Sstevel@tonic-gate 				 * Copy packet contents out to user space if
4317c478bd9Sstevel@tonic-gate 				 * requested.  Bail on an error.
4327c478bd9Sstevel@tonic-gate 				 */
433f4b3ec61Sdh 				m = ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext];
4347c478bd9Sstevel@tonic-gate 				len = MSGDSIZE(m);
4357c478bd9Sstevel@tonic-gate 				if (len > auth.fra_len)
4367c478bd9Sstevel@tonic-gate 					len = auth.fra_len;
4377c478bd9Sstevel@tonic-gate 				auth.fra_len = len;
4387c478bd9Sstevel@tonic-gate 				for (t = auth.fra_buf; m && (len > 0); ) {
4397c478bd9Sstevel@tonic-gate 					i = MIN(M_LEN(m), len);
4407c478bd9Sstevel@tonic-gate 					error = copyoutptr(MTOD(m, char *),
4417c478bd9Sstevel@tonic-gate 							  t, i);
4427c478bd9Sstevel@tonic-gate 					len -= i;
4437c478bd9Sstevel@tonic-gate 					t += i;
4447c478bd9Sstevel@tonic-gate 					if (error != 0)
4457c478bd9Sstevel@tonic-gate 						break;
4467c478bd9Sstevel@tonic-gate 				}
4477c478bd9Sstevel@tonic-gate 			}
448f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
4497c478bd9Sstevel@tonic-gate 			if (error != 0)
4507c478bd9Sstevel@tonic-gate 				break;
4517c478bd9Sstevel@tonic-gate 			SPL_NET(s);
452f4b3ec61Sdh 			WRITE_ENTER(&ifs->ifs_ipf_auth);
453f4b3ec61Sdh 			ifs->ifs_fr_authnext++;
454f4b3ec61Sdh 			if (ifs->ifs_fr_authnext == ifs->ifs_fr_authsize)
455f4b3ec61Sdh 				ifs->ifs_fr_authnext = 0;
456f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
4577c478bd9Sstevel@tonic-gate 			SPL_X(s);
4587c478bd9Sstevel@tonic-gate 			return 0;
4597c478bd9Sstevel@tonic-gate 		}
460f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
4617c478bd9Sstevel@tonic-gate 		/*
4627c478bd9Sstevel@tonic-gate 		 * We exit ipf_global here because a program that enters in
4637c478bd9Sstevel@tonic-gate 		 * here will have a lock on it and goto sleep having this lock.
4647c478bd9Sstevel@tonic-gate 		 * If someone were to do an 'ipf -D' the system would then
4657c478bd9Sstevel@tonic-gate 		 * deadlock.  The catch with releasing it here is that the
4667c478bd9Sstevel@tonic-gate 		 * caller of this function expects it to be held when we
4677c478bd9Sstevel@tonic-gate 		 * return so we have to reacquire it in here.
4687c478bd9Sstevel@tonic-gate 		 */
469f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
4707c478bd9Sstevel@tonic-gate 
471f4b3ec61Sdh 		MUTEX_ENTER(&ifs->ifs_ipf_authmx);
4727c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
4737c478bd9Sstevel@tonic-gate # if	SOLARIS
4747c478bd9Sstevel@tonic-gate 		error = 0;
475f4b3ec61Sdh 		if (!cv_wait_sig(&ifs->ifs_ipfauthwait, &ifs->ifs_ipf_authmx.ipf_lk))
4767c478bd9Sstevel@tonic-gate 			error = EINTR;
4777c478bd9Sstevel@tonic-gate # else /* SOLARIS */
4787c478bd9Sstevel@tonic-gate #  ifdef __hpux
4797c478bd9Sstevel@tonic-gate 		{
4807c478bd9Sstevel@tonic-gate 		lock_t *l;
4817c478bd9Sstevel@tonic-gate 
482f4b3ec61Sdh 		l = get_sleep_lock(&ifs->ifs_fr_authnext);
483f4b3ec61Sdh 		error = sleep(&ifs->ifs_fr_authnext, PZERO+1);
4847c478bd9Sstevel@tonic-gate 		spinunlock(l);
4857c478bd9Sstevel@tonic-gate 		}
4867c478bd9Sstevel@tonic-gate #  else
4877c478bd9Sstevel@tonic-gate #   ifdef __osf__
488f4b3ec61Sdh 		error = mpsleep(&ifs->ifs_fr_authnext, PSUSP|PCATCH,
489f4b3ec61Sdh 				"fr_authnext", 0,
490f4b3ec61Sdh 				&ifs->ifs_ipf_authmx, MS_LOCK_SIMPLE);
4917c478bd9Sstevel@tonic-gate #   else
492f4b3ec61Sdh 		error = SLEEP(&ifs->ifs_fr_authnext, "fr_authnext");
4937c478bd9Sstevel@tonic-gate #   endif /* __osf__ */
4947c478bd9Sstevel@tonic-gate #  endif /* __hpux */
4957c478bd9Sstevel@tonic-gate # endif /* SOLARIS */
4967c478bd9Sstevel@tonic-gate #endif
497f4b3ec61Sdh 		MUTEX_EXIT(&ifs->ifs_ipf_authmx);
498f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_global);
4997c478bd9Sstevel@tonic-gate 		if (error == 0) {
500f4b3ec61Sdh 			READ_ENTER(&ifs->ifs_ipf_auth);
5017c478bd9Sstevel@tonic-gate 			goto fr_authioctlloop;
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate 		break;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	case SIOCAUTHR:
5067c478bd9Sstevel@tonic-gate 		error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
5077c478bd9Sstevel@tonic-gate 		if (error != 0)
5087c478bd9Sstevel@tonic-gate 			return error;
5097c478bd9Sstevel@tonic-gate 		SPL_NET(s);
510f4b3ec61Sdh 		WRITE_ENTER(&ifs->ifs_ipf_auth);
5117c478bd9Sstevel@tonic-gate 		i = au->fra_index;
512f4b3ec61Sdh 		fra = ifs->ifs_fr_auth + i;
513f4b3ec61Sdh 		if ((i < 0) || (i >= ifs->ifs_fr_authsize) ||
5147c478bd9Sstevel@tonic-gate 		    (fra->fra_info.fin_id != au->fra_info.fin_id)) {
515f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
5167c478bd9Sstevel@tonic-gate 			SPL_X(s);
5177c478bd9Sstevel@tonic-gate 			return ESRCH;
5187c478bd9Sstevel@tonic-gate 		}
519f4b3ec61Sdh 		m = ifs->ifs_fr_authpkts[i];
5207c478bd9Sstevel@tonic-gate 		fra->fra_index = -2;
5217c478bd9Sstevel@tonic-gate 		fra->fra_pass = au->fra_pass;
522f4b3ec61Sdh 		ifs->ifs_fr_authpkts[i] = NULL;
523f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
5247c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
525381a2a9aSdr 		if (fra->fra_info.fin_v == 4) {
526f4b3ec61Sdh 			net_data_p = ifs->ifs_ipf_ipv4;
527381a2a9aSdr 		} else if (fra->fra_info.fin_v == 6) {
528f4b3ec61Sdh 			net_data_p = ifs->ifs_ipf_ipv6;
529381a2a9aSdr 		} else {
530381a2a9aSdr 			return (-1);
531381a2a9aSdr 		}
532381a2a9aSdr 
533381a2a9aSdr 		/*
534381a2a9aSdr 		 * We're putting the packet back on the same interface
535