xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_auth.c (revision bb1d9de5)
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 
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");
1547c478bd9Sstevel@tonic-gate #if 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  */
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  */
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
3377c478bd9Sstevel@tonic-gate #if 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 
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;
371381a2a9aSdr 	net_data_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 		}
401*bb1d9de5SJohn 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
535381a2a9aSdr 		 * queue that it was originally seen on so that it can
536381a2a9aSdr 		 * progress through the system properly, with the result
537381a2a9aSdr 		 * of the auth check done.
538381a2a9aSdr 		 */
539381a2a9aSdr 		inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp;
540381a2a9aSdr 
5417c478bd9Sstevel@tonic-gate 		if ((m != NULL) && (au->fra_info.fin_out != 0)) {
5427c478bd9Sstevel@tonic-gate # ifdef MENTAT
543381a2a9aSdr 			inj_data.ni_packet = m;
544381a2a9aSdr 			ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data);
545381a2a9aSdr 
546381a2a9aSdr 			if (ret < 0)
547f4b3ec61Sdh 				ifs->ifs_fr_authstats.fas_sendfail++;
548381a2a9aSdr 			else
549f4b3ec61Sdh 				ifs->ifs_fr_authstats.fas_sendok++;
5507c478bd9Sstevel@tonic-gate # else /* MENTAT */
551ab25eeb5Syz #  if defined(linux) || defined(AIX)
552ab25eeb5Syz #  else
553ab25eeb5Syz #   if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \
554ab25eeb5Syz        (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \
555ab25eeb5Syz        (defined(__FreeBSD__) && (__FreeBSD_version >= 470102)))
5567c478bd9Sstevel@tonic-gate 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL,
5577c478bd9Sstevel@tonic-gate 					  NULL);
558ab25eeb5Syz #   else
5597c478bd9Sstevel@tonic-gate 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
560ab25eeb5Syz #   endif
5617c478bd9Sstevel@tonic-gate 			if (error != 0)
562f4b3ec61Sdh 				ifs->ifs_fr_authstats.fas_sendfail++;
5637c478bd9Sstevel@tonic-gate 			else
564f4b3ec61Sdh 				ifs->ifs_fr_authstats.fas_sendok++;
565381a2a9aSdr #  endif /* Linux */
566381a2a9aSdr # endif /* MENTAT */
5677c478bd9Sstevel@tonic-gate 		} else if (m) {
5687c478bd9Sstevel@tonic-gate # ifdef MENTAT
569381a2a9aSdr 			inj_data.ni_packet = m;
570381a2a9aSdr 			ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data);
5717c478bd9Sstevel@tonic-gate # else /* MENTAT */
572ab25eeb5Syz #  if defined(linux) || defined(AIX)
573ab25eeb5Syz #  else
574ab25eeb5Syz #   if (__FreeBSD_version >= 501000)
575ab25eeb5Syz 			netisr_dispatch(NETISR_IP, m);
576ab25eeb5Syz #   else
577ab25eeb5Syz #    if (IRIX >= 60516)
578ab25eeb5Syz 			ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd;
579ab25eeb5Syz #    else
5807c478bd9Sstevel@tonic-gate 			ifq = &ipintrq;
581ab25eeb5Syz #    endif
5827c478bd9Sstevel@tonic-gate 			if (IF_QFULL(ifq)) {
5837c478bd9Sstevel@tonic-gate 				IF_DROP(ifq);
584ab25eeb5Syz 				FREE_MB_T(m);
5857c478bd9Sstevel@tonic-gate 				error = ENOBUFS;
5867c478bd9Sstevel@tonic-gate 			} else {
5877c478bd9Sstevel@tonic-gate 				IF_ENQUEUE(ifq, m);
588ab25eeb5Syz #    if IRIX < 60500
5897c478bd9Sstevel@tonic-gate 				schednetisr(NETISR_IP);
590ab25eeb5Syz #    endif
5917c478bd9Sstevel@tonic-gate 			}
592ab25eeb5Syz #   endif
593ab25eeb5Syz #  endif /* Linux */
5947c478bd9Sstevel@tonic-gate # endif /* MENTAT */
5957c478bd9Sstevel@tonic-gate 			if (error != 0)
596f4b3ec61Sdh 				ifs->ifs_fr_authstats.fas_quefail++;
5977c478bd9Sstevel@tonic-gate 			else
598f4b3ec61Sdh 				ifs->ifs_fr_authstats.fas_queok++;
5997c478bd9Sstevel@tonic-gate 		} else
6007c478bd9Sstevel@tonic-gate 			error = EINVAL;
6017c478bd9Sstevel@tonic-gate # ifdef MENTAT
6027c478bd9Sstevel@tonic-gate 		if (error != 0)
6037c478bd9Sstevel@tonic-gate 			error = EINVAL;
6047c478bd9Sstevel@tonic-gate # else /* MENTAT */
6057c478bd9Sstevel@tonic-gate 		/*
6067c478bd9Sstevel@tonic-gate 		 * If we experience an error which will result in the packet
6077c478bd9Sstevel@tonic-gate 		 * not being processed, make sure we advance to the next one.
608ab25eeb5Syz 		 */
6097c478bd9Sstevel@tonic-gate 		if (error == ENOBUFS) {
610f4b3ec61Sdh 			ifs->ifs_fr_authused--;
6117c478bd9Sstevel@tonic-gate 			fra->fra_index = -1;
6127c478bd9Sstevel@tonic-gate 			fra->fra_pass = 0;
613f4b3ec61Sdh 			if (i == ifs->ifs_fr_authstart) {
6147c478bd9Sstevel@tonic-gate 				while (fra->fra_index == -1) {
6157c478bd9Sstevel@tonic-gate 					i++;
616f4b3ec61Sdh 					if (i == ifs->ifs_fr_authsize)
6177c478bd9Sstevel@tonic-gate 						i = 0;
618f4b3ec61Sdh 					ifs->ifs_fr_authstart = i;
619f4b3ec61Sdh 					if (i == ifs->ifs_fr_authend)
6207c478bd9Sstevel@tonic-gate 						break;
6217c478bd9Sstevel@tonic-gate 				}
622f4b3ec61Sdh 				if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) {
623f4b3ec61Sdh 					ifs->ifs_fr_authnext = 0;
624f4b3ec61Sdh 					ifs->ifs_fr_authstart = 0;
625f4b3ec61Sdh 					ifs->ifs_fr_authend = 0;
6267c478bd9Sstevel@tonic-gate 				}
6277c478bd9Sstevel@tonic-gate 			}
6287c478bd9Sstevel@tonic-gate 		}
6297c478bd9Sstevel@tonic-gate # endif /* MENTAT */
6307c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
6317c478bd9Sstevel@tonic-gate 		SPL_X(s);
6327c478bd9Sstevel@tonic-gate 		break;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	default :
6357c478bd9Sstevel@tonic-gate 		error = EINVAL;
6367c478bd9Sstevel@tonic-gate 		break;
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 	return error;
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  * Free all network buffer memory used to keep saved packets.
6447c478bd9Sstevel@tonic-gate  */
645f4b3ec61Sdh void fr_authunload(ifs)
646f4b3ec61Sdh ipf_stack_t *ifs;
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	register int i;
6497c478bd9Sstevel@tonic-gate 	register frauthent_t *fae, **faep;
6507c478bd9Sstevel@tonic-gate 	frentry_t *fr, **frp;
6517c478bd9Sstevel@tonic-gate 	mb_t *m;
6527c478bd9Sstevel@tonic-gate 
653f4b3ec61Sdh 	if (ifs->ifs_fr_auth != NULL) {
654f4b3ec61Sdh 		KFREES(ifs->ifs_fr_auth,
655f4b3ec61Sdh 		       ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth));
656f4b3ec61Sdh 		ifs->ifs_fr_auth = NULL;
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate 
659f4b3ec61Sdh 	if (ifs->ifs_fr_authpkts != NULL) {
660f4b3ec61Sdh 		for (i = 0; i < ifs->ifs_fr_authsize; i++) {
661f4b3ec61Sdh 			m = ifs->ifs_fr_authpkts[i];
6627c478bd9Sstevel@tonic-gate 			if (m != NULL) {
6637c478bd9Sstevel@tonic-gate 				FREE_MB_T(m);
664f4b3ec61Sdh 				ifs->ifs_fr_authpkts[i] = NULL;
6657c478bd9Sstevel@tonic-gate 			}
6667c478bd9Sstevel@tonic-gate 		}
667f4b3ec61Sdh 		KFREES(ifs->ifs_fr_authpkts,
668f4b3ec61Sdh 		       ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts));
669f4b3ec61Sdh 		ifs->ifs_fr_authpkts = NULL;
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 
672f4b3ec61Sdh 	faep = &ifs->ifs_fae_list;
6737c478bd9Sstevel@tonic-gate 	while ((fae = *faep) != NULL) {
6747c478bd9Sstevel@tonic-gate 		*faep = fae->fae_next;
6757c478bd9Sstevel@tonic-gate 		KFREE(fae);
6767c478bd9Sstevel@tonic-gate 	}
677f4b3ec61Sdh 	ifs->ifs_ipauth = NULL;
6787c478bd9Sstevel@tonic-gate 
679f4b3ec61Sdh 	if (ifs->ifs_fr_authlist != NULL) {
680f4b3ec61Sdh 		for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) {
6817c478bd9Sstevel@tonic-gate 			if (fr->fr_ref == 1) {
6827c478bd9Sstevel@tonic-gate 				*frp = fr->fr_next;
6837c478bd9Sstevel@tonic-gate 				KFREE(fr);
6847c478bd9Sstevel@tonic-gate 			} else
6857c478bd9Sstevel@tonic-gate 				frp = &fr->fr_next;
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
689f4b3ec61Sdh 	if (ifs->ifs_fr_auth_init == 1) {
6907c478bd9Sstevel@tonic-gate # if SOLARIS && defined(_KERNEL)
691f4b3ec61Sdh 		cv_destroy(&ifs->ifs_ipfauthwait);
6927c478bd9Sstevel@tonic-gate # endif
693f4b3ec61Sdh 		MUTEX_DESTROY(&ifs->ifs_ipf_authmx);
694f4b3ec61Sdh 		RW_DESTROY(&ifs->ifs_ipf_auth);
6957c478bd9Sstevel@tonic-gate 
696f4b3ec61Sdh 		ifs->ifs_fr_auth_init = 0;
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  * Slowly expire held auth records.  Timeouts are set
7037c478bd9Sstevel@tonic-gate  * in expectation of this being called twice per second.
7047c478bd9Sstevel@tonic-gate  */
705f4b3ec61Sdh void fr_authexpire(ifs)
706f4b3ec61Sdh ipf_stack_t *ifs;
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	register int i;
7097c478bd9Sstevel@tonic-gate 	register frauth_t *fra;
7107c478bd9Sstevel@tonic-gate 	register frauthent_t *fae, **faep;
7117c478bd9Sstevel@tonic-gate 	register frentry_t *fr, **frp;
7127c478bd9Sstevel@tonic-gate 	mb_t *m;
713ab25eeb5Syz 	SPL_INT(s);
7147c478bd9Sstevel@tonic-gate 
715f4b3ec61Sdh 	if (ifs->ifs_fr_auth_lock)
7167c478bd9Sstevel@tonic-gate 		return;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	SPL_NET(s);
719f4b3ec61Sdh 	WRITE_ENTER(&ifs->ifs_ipf_auth);
720f4b3ec61Sdh 	for (i = 0, fra = ifs->ifs_fr_auth; i < ifs->ifs_fr_authsize; i++, fra++) {
7217c478bd9Sstevel@tonic-gate 		fra->fra_age--;
722f4b3ec61Sdh 		if ((fra->fra_age == 0) && (m = ifs->ifs_fr_authpkts[i])) {
7237c478bd9Sstevel@tonic-gate 			FREE_MB_T(m);
724f4b3ec61Sdh 			ifs->ifs_fr_authpkts[i] = NULL;
725f4b3ec61Sdh 			ifs->ifs_fr_auth[i].fra_index = -1;
726f4b3ec61Sdh 			ifs->ifs_fr_authstats.fas_expire++;
727f4b3ec61Sdh 			ifs->ifs_fr_authused--;
7287c478bd9Sstevel@tonic-gate 		}
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 
731f4b3ec61Sdh 	for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) {
7327c478bd9Sstevel@tonic-gate 		fae->fae_age--;
7337c478bd9Sstevel@tonic-gate 		if (fae->fae_age == 0) {
7347c478bd9Sstevel@tonic-gate 			*faep = fae->fae_next;
7357c478bd9Sstevel@tonic-gate 			KFREE(fae);
736f4b3ec61Sdh 			ifs->ifs_fr_authstats.fas_expire++;
7377c478bd9Sstevel@tonic-gate 		} else
7387c478bd9Sstevel@tonic-gate 			faep = &fae->fae_next;
7397c478bd9Sstevel@tonic-gate 	}
740f4b3ec61Sdh 	if (ifs->ifs_fae_list != NULL)
741f4b3ec61Sdh 		ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr;
7427c478bd9Sstevel@tonic-gate 	else
743f4b3ec61Sdh 		ifs->ifs_ipauth = NULL;
7447c478bd9Sstevel@tonic-gate 
745f4b3ec61Sdh 	for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) {
7467c478bd9Sstevel@tonic-gate 		if (fr->fr_ref == 1) {
7477c478bd9Sstevel@tonic-gate 			*frp = fr->fr_next;
7487c478bd9Sstevel@tonic-gate 			KFREE(fr);
7497c478bd9Sstevel@tonic-gate 		} else
7507c478bd9Sstevel@tonic-gate 			frp = &fr->fr_next;
7517c478bd9Sstevel@tonic-gate 	}
752f4b3ec61Sdh 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
7537c478bd9Sstevel@tonic-gate 	SPL_X(s);
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
756f4b3ec61Sdh int fr_preauthcmd(cmd, fr, frptr, ifs)
757ab25eeb5Syz ioctlcmd_t cmd;
7587c478bd9Sstevel@tonic-gate frentry_t *fr, **frptr;
759f4b3ec61Sdh ipf_stack_t *ifs;
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate 	frauthent_t *fae, **faep;
7627c478bd9Sstevel@tonic-gate 	int error = 0;
763ab25eeb5Syz 	SPL_INT(s);
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
7667c478bd9Sstevel@tonic-gate 		return EIO;
7677c478bd9Sstevel@tonic-gate 
768f4b3ec61Sdh 	for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) {
7697c478bd9Sstevel@tonic-gate 		if (&fae->fae_fr == fr)
7707c478bd9Sstevel@tonic-gate 			break;
7717c478bd9Sstevel@tonic-gate 		else
7727c478bd9Sstevel@tonic-gate 			faep = &fae->fae_next;
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 
775ab25eeb5Syz 	if (cmd == (ioctlcmd_t)SIOCRMAFR) {
7767c478bd9Sstevel@tonic-gate 		if (fr == NULL || frptr == NULL)
7777c478bd9Sstevel@tonic-gate 			error = EINVAL;
7787c478bd9Sstevel@tonic-gate 		else if (fae == NULL)
7797c478bd9Sstevel@tonic-gate 			error = ESRCH;
7807c478bd9Sstevel@tonic-gate 		else {
7817c478bd9Sstevel@tonic-gate 			SPL_NET(s);
782f4b3ec61Sdh 			WRITE_ENTER(&ifs->ifs_ipf_auth);
7837c478bd9Sstevel@tonic-gate 			*faep = fae->fae_next;
784f4b3ec61Sdh 			if (ifs->ifs_ipauth == &fae->fae_fr)
785f4b3ec61Sdh 				ifs->ifs_ipauth = ifs->ifs_fae_list ?
786f4b3ec61Sdh 				    &ifs->ifs_fae_list->fae_fr : NULL;
787f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
7887c478bd9Sstevel@tonic-gate 			SPL_X(s);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 			KFREE(fae);
7917c478bd9Sstevel@tonic-gate 		}
7927c478bd9Sstevel@tonic-gate 	} else if (fr != NULL && frptr != NULL) {
7937c478bd9Sstevel@tonic-gate 		KMALLOC(fae, frauthent_t *);
7947c478bd9Sstevel@tonic-gate 		if (fae != NULL) {
7957c478bd9Sstevel@tonic-gate 			bcopy((char *)fr, (char *)&fae->fae_fr,
7967c478bd9Sstevel@tonic-gate 			      sizeof(*fr));
7977c478bd9Sstevel@tonic-gate 			SPL_NET(s);
798f4b3ec61Sdh 			WRITE_ENTER(&ifs->ifs_ipf_auth);
799f4b3ec61Sdh 			fae->fae_age = ifs->ifs_fr_defaultauthage;
8007c478bd9Sstevel@tonic-gate 			fae->fae_fr.fr_hits = 0;
8017c478bd9Sstevel@tonic-gate 			fae->fae_fr.fr_next = *frptr;
802f4b3ec61Sdh 			fae->fae_ref = 1;
8037c478bd9Sstevel@tonic-gate 			*frptr = &fae->fae_fr;
8047c478bd9Sstevel@tonic-gate 			fae->fae_next = *faep;
8057c478bd9Sstevel@tonic-gate 			*faep = fae;
806f4b3ec61Sdh 			ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr;
807f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
8087c478bd9Sstevel@tonic-gate 			SPL_X(s);
8097c478bd9Sstevel@tonic-gate 		} else
8107c478bd9Sstevel@tonic-gate 			error = ENOMEM;
8117c478bd9Sstevel@tonic-gate 	} else
8127c478bd9Sstevel@tonic-gate 		error = EINVAL;
8137c478bd9Sstevel@tonic-gate 	return error;
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate /*
818ab25eeb5Syz  * Flush held packets.
819ab25eeb5Syz  * Must already be properly SPL'ed and Locked on &ipf_auth.
820ab25eeb5Syz  *
8217c478bd9Sstevel@tonic-gate  */
822f4b3ec61Sdh int fr_authflush(ifs)
823f4b3ec61Sdh ipf_stack_t *ifs;
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 	register int i, num_flushed;
8267c478bd9Sstevel@tonic-gate 	mb_t *m;
8277c478bd9Sstevel@tonic-gate 
828f4b3ec61Sdh 	if (ifs->ifs_fr_auth_lock)
8297c478bd9Sstevel@tonic-gate 		return -1;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	num_flushed = 0;
8327c478bd9Sstevel@tonic-gate 
833f4b3ec61Sdh 	for (i = 0 ; i < ifs->ifs_fr_authsize; i++) {
834f4b3ec61Sdh 		m = ifs->ifs_fr_authpkts[i];
8357c478bd9Sstevel@tonic-gate 		if (m != NULL) {
8367c478bd9Sstevel@tonic-gate 			FREE_MB_T(m);
837f4b3ec61Sdh 			ifs->ifs_fr_authpkts[i] = NULL;
838f4b3ec61Sdh 			ifs->ifs_fr_auth[i].fra_index = -1;
8397c478bd9Sstevel@tonic-gate 			/* perhaps add & use a flush counter inst.*/
840f4b3ec61Sdh 			ifs->ifs_fr_authstats.fas_expire++;
841f4b3ec61Sdh 			ifs->ifs_fr_authused--;
8427c478bd9Sstevel@tonic-gate 			num_flushed++;
8437c478bd9Sstevel@tonic-gate 		}
8447c478bd9Sstevel@tonic-gate 	}
8457c478bd9Sstevel@tonic-gate 
846f4b3ec61Sdh 	ifs->ifs_fr_authstart = 0;
847f4b3ec61Sdh 	ifs->ifs_fr_authend = 0;
848f4b3ec61Sdh 	ifs->ifs_fr_authnext = 0;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	return num_flushed;
8517c478bd9Sstevel@tonic-gate }
852f4b3ec61Sdh 
853f4b3ec61Sdh /* ------------------------------------------------------------------------ */
854f4b3ec61Sdh /* Function:    fr_authgeniter                                              */
855f4b3ec61Sdh /* Returns:     int - 0 == success, else error                              */
856f4b3ec61Sdh /* Parameters:  token(I) - pointer to ipftoken structure                    */
857f4b3ec61Sdh /*              itp(I)   - pointer to ipfgeniter structure                  */
858f4b3ec61Sdh /*                                                                          */
859f4b3ec61Sdh /* ------------------------------------------------------------------------ */
860f4b3ec61Sdh int fr_authgeniter(token, itp, ifs)
861f4b3ec61Sdh ipftoken_t *token;
862f4b3ec61Sdh ipfgeniter_t *itp;
863f4b3ec61Sdh ipf_stack_t *ifs;
864f4b3ec61Sdh {
865f4b3ec61Sdh 	frauthent_t *fae, *next, zero;
866f4b3ec61Sdh 	int error;
867f4b3ec61Sdh 
868f4b3ec61Sdh 	if (itp->igi_data == NULL)
869f4b3ec61Sdh 		return EFAULT;
870f4b3ec61Sdh 
871f4b3ec61Sdh 	if (itp->igi_type != IPFGENITER_AUTH)
872f4b3ec61Sdh 		return EINVAL;
873f4b3ec61Sdh 
874f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_auth);
875786c7074Sjojemann 
876786c7074Sjojemann 	/*
877786c7074Sjojemann 	 * Retrieve "previous" entry from token and find the next entry.
878786c7074Sjojemann 	 */
879786c7074Sjojemann 	fae = token->ipt_data;
880f4b3ec61Sdh 	if (fae == NULL) {
881f4b3ec61Sdh 		next = ifs->ifs_fae_list;
882f4b3ec61Sdh 	} else {
883f4b3ec61Sdh 		next = fae->fae_next;
884f4b3ec61Sdh 	}
885f4b3ec61Sdh 
886786c7074Sjojemann 	/*
887786c7074Sjojemann 	 * If we found an entry, add reference to it and update token.
888786c7074Sjojemann 	 * Otherwise, zero out data to be returned and NULL out token.
889786c7074Sjojemann 	 */
890f4b3ec61Sdh 	if (next != NULL) {
891f4b3ec61Sdh 		ATOMIC_INC(next->fae_ref);
892786c7074Sjojemann 		token->ipt_data = next;
893f4b3ec61Sdh 	} else {
894f4b3ec61Sdh 		bzero(&zero, sizeof(zero));
895f4b3ec61Sdh 		next = &zero;
896786c7074Sjojemann 		token->ipt_data = NULL;
897f4b3ec61Sdh 	}
898f4b3ec61Sdh 
899f4b3ec61Sdh 	/*
900786c7074Sjojemann 	 * Safe to release the lock now that we have a reference.
901f4b3ec61Sdh 	 */
902786c7074Sjojemann 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
903f4b3ec61Sdh 
904f4b3ec61Sdh 	/*
905786c7074Sjojemann 	 * Copy out the data and clean up references and token as needed.
906f4b3ec61Sdh 	 */
907f4b3ec61Sdh 	error = COPYOUT(next, itp->igi_data, sizeof(*next));
908f4b3ec61Sdh 	if (error != 0)
909f4b3ec61Sdh 		error = EFAULT;
910786c7074Sjojemann 	if (token->ipt_data == NULL) {
911786c7074Sjojemann 		ipf_freetoken(token, ifs);
912786c7074Sjojemann 	} else {
913786c7074Sjojemann 		if (fae != NULL) {
914786c7074Sjojemann 			WRITE_ENTER(&ifs->ifs_ipf_auth);
915786c7074Sjojemann 			fr_authderef(&fae);
916786c7074Sjojemann 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
917786c7074Sjojemann 		}
918786c7074Sjojemann 		if (next->fae_next == NULL)
919786c7074Sjojemann 			ipf_freetoken(token, ifs);
920786c7074Sjojemann 	}
921f4b3ec61Sdh 	return error;
922f4b3ec61Sdh }
923f4b3ec61Sdh 
924f4b3ec61Sdh 
925f4b3ec61Sdh void fr_authderef(faep)
926f4b3ec61Sdh frauthent_t **faep;
927f4b3ec61Sdh {
928f4b3ec61Sdh 	frauthent_t *fae;
929f4b3ec61Sdh 
930f4b3ec61Sdh 	fae = *faep;
931f4b3ec61Sdh 	*faep = NULL;
932f4b3ec61Sdh 
933f4b3ec61Sdh 	fae->fae_ref--;
934f4b3ec61Sdh 	if (fae->fae_ref == 0) {
935f4b3ec61Sdh 		KFREE(fae);
936f4b3ec61Sdh 	}
937f4b3ec61Sdh }
938