xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_auth.c (revision 786c70747614169d73f085365beecfbd6861ffcf)
1ab25eeb5Syz155240 /*
2ab25eeb5Syz155240  * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
3ab25eeb5Syz155240  *
4ab25eeb5Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
5f4b3ec61Sdh155122  *
6*786c7074Sjojemann  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
7381a2a9aSdr146992  * Use is subject to license terms.
8381a2a9aSdr146992  */
9381a2a9aSdr146992 
10381a2a9aSdr146992 #pragma ident	"%Z%%M%	%I%	%E% SMI"
11381a2a9aSdr146992 
12ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL)
13ab25eeb5Syz155240 # undef KERNEL
14ab25eeb5Syz155240 # undef _KERNEL
15ab25eeb5Syz155240 # define        KERNEL	1
16ab25eeb5Syz155240 # define        _KERNEL	1
17ab25eeb5Syz155240 #endif
18ab25eeb5Syz155240 #include <sys/errno.h>
19ab25eeb5Syz155240 #include <sys/types.h>
20ab25eeb5Syz155240 #include <sys/param.h>
21ab25eeb5Syz155240 #include <sys/time.h>
22ab25eeb5Syz155240 #include <sys/file.h>
23ab25eeb5Syz155240 #if !defined(_KERNEL)
24ab25eeb5Syz155240 # include <stdio.h>
25ab25eeb5Syz155240 # include <stdlib.h>
26ab25eeb5Syz155240 # include <string.h>
27ab25eeb5Syz155240 # define _KERNEL
28ab25eeb5Syz155240 # ifdef __OpenBSD__
29ab25eeb5Syz155240 struct file;
30ab25eeb5Syz155240 # endif
31ab25eeb5Syz155240 # include <sys/uio.h>
32ab25eeb5Syz155240 # undef _KERNEL
33ab25eeb5Syz155240 #endif
34ab25eeb5Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
35ab25eeb5Syz155240 # include <sys/filio.h>
36ab25eeb5Syz155240 # include <sys/fcntl.h>
37ab25eeb5Syz155240 #else
38ab25eeb5Syz155240 # include <sys/ioctl.h>
39ab25eeb5Syz155240 #endif
40ab25eeb5Syz155240 #if !defined(linux)
41ab25eeb5Syz155240 # include <sys/protosw.h>
42ab25eeb5Syz155240 #endif
43ab25eeb5Syz155240 #include <sys/socket.h>
44ab25eeb5Syz155240 #if defined(_KERNEL)
45ab25eeb5Syz155240 # include <sys/systm.h>
46ab25eeb5Syz155240 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux)
47ab25eeb5Syz155240 #  include <sys/mbuf.h>
48ab25eeb5Syz155240 # endif
49ab25eeb5Syz155240 #endif
50ab25eeb5Syz155240 #if defined(__SVR4) || defined(__svr4__)
51ab25eeb5Syz155240 # include <sys/filio.h>
52ab25eeb5Syz155240 # include <sys/byteorder.h>
53ab25eeb5Syz155240 # ifdef _KERNEL
54ab25eeb5Syz155240 #  include <sys/dditypes.h>
55ab25eeb5Syz155240 # endif
56ab25eeb5Syz155240 # include <sys/stream.h>
57ab25eeb5Syz155240 # include <sys/kmem.h>
58381a2a9aSdr146992 # include <sys/neti.h>
59ab25eeb5Syz155240 #endif
60ab25eeb5Syz155240 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000)
61ab25eeb5Syz155240 # include <sys/queue.h>
62ab25eeb5Syz155240 #endif
63ab25eeb5Syz155240 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
64ab25eeb5Syz155240 # include <machine/cpu.h>
65ab25eeb5Syz155240 #endif
66ab25eeb5Syz155240 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
67ab25eeb5Syz155240 # include <sys/proc.h>
68ab25eeb5Syz155240 #endif
69ab25eeb5Syz155240 #include <net/if.h>
70ab25eeb5Syz155240 #ifdef sun
71ab25eeb5Syz155240 # include <net/af.h>
72ab25eeb5Syz155240 #endif
73ab25eeb5Syz155240 #include <net/route.h>
74ab25eeb5Syz155240 #include <netinet/in.h>
75ab25eeb5Syz155240 #include <netinet/in_systm.h>
76ab25eeb5Syz155240 #include <netinet/ip.h>
77ab25eeb5Syz155240 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi)
78ab25eeb5Syz155240 # define	KERNEL
79ab25eeb5Syz155240 # define	_KERNEL
80ab25eeb5Syz155240 # define	NOT_KERNEL
81ab25eeb5Syz155240 #endif
82ab25eeb5Syz155240 #if !defined(linux)
83ab25eeb5Syz155240 # include <netinet/ip_var.h>
84ab25eeb5Syz155240 #endif
85ab25eeb5Syz155240 #ifdef	NOT_KERNEL
86ab25eeb5Syz155240 # undef	_KERNEL
87ab25eeb5Syz155240 # undef	KERNEL
88ab25eeb5Syz155240 #endif
89ab25eeb5Syz155240 #include <netinet/tcp.h>
90ab25eeb5Syz155240 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */
91ab25eeb5Syz155240 extern struct ifqueue   ipintrq;		/* ip packet input queue */
92ab25eeb5Syz155240 #else
93ab25eeb5Syz155240 # if !defined(__hpux) && !defined(linux)
94ab25eeb5Syz155240 #  if __FreeBSD_version >= 300000
95ab25eeb5Syz155240 #   include <net/if_var.h>
96ab25eeb5Syz155240 #   if __FreeBSD_version >= 500042
97ab25eeb5Syz155240 #    define IF_QFULL _IF_QFULL
98ab25eeb5Syz155240 #    define IF_DROP _IF_DROP
99ab25eeb5Syz155240 #   endif /* __FreeBSD_version >= 500042 */
100ab25eeb5Syz155240 #  endif
101ab25eeb5Syz155240 #  include <netinet/in_var.h>
102ab25eeb5Syz155240 #  include <netinet/tcp_fsm.h>
103ab25eeb5Syz155240 # endif
104ab25eeb5Syz155240 #endif
105ab25eeb5Syz155240 #include <netinet/udp.h>
106ab25eeb5Syz155240 #include <netinet/ip_icmp.h>
107ab25eeb5Syz155240 #include "netinet/ip_compat.h"
108ab25eeb5Syz155240 #include <netinet/tcpip.h>
109f4b3ec61Sdh155122 #include "netinet/ipf_stack.h"
110ab25eeb5Syz155240 #include "netinet/ip_fil.h"
111ab25eeb5Syz155240 #include "netinet/ip_auth.h"
112ab25eeb5Syz155240 #if !defined(MENTAT) && !defined(linux)
113ab25eeb5Syz155240 # include <net/netisr.h>
114ab25eeb5Syz155240 # ifdef __FreeBSD__
115ab25eeb5Syz155240 #  include <machine/cpufunc.h>
116ab25eeb5Syz155240 # endif
117ab25eeb5Syz155240 #endif
118ab25eeb5Syz155240 #if (__FreeBSD_version >= 300000)
119ab25eeb5Syz155240 # include <sys/malloc.h>
120ab25eeb5Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
121ab25eeb5Syz155240 #  include <sys/libkern.h>
122ab25eeb5Syz155240 #  include <sys/systm.h>
123ab25eeb5Syz155240 # endif
124ab25eeb5Syz155240 #endif
125ab25eeb5Syz155240 /* END OF INCLUDES */
126ab25eeb5Syz155240 
127ab25eeb5Syz155240 #if !defined(lint)
128ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $";
129ab25eeb5Syz155240 #endif
130ab25eeb5Syz155240 
131f4b3ec61Sdh155122 void fr_authderef __P((frauthent_t **));
132f4b3ec61Sdh155122 int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
133ab25eeb5Syz155240 
134ab25eeb5Syz155240 
135f4b3ec61Sdh155122 int fr_authinit(ifs)
136f4b3ec61Sdh155122 ipf_stack_t *ifs;
137ab25eeb5Syz155240 {
138f4b3ec61Sdh155122 	KMALLOCS(ifs->ifs_fr_auth, frauth_t *,
139f4b3ec61Sdh155122 		 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth));
140f4b3ec61Sdh155122 	if (ifs->ifs_fr_auth != NULL)
141f4b3ec61Sdh155122 		bzero((char *)ifs->ifs_fr_auth,
142f4b3ec61Sdh155122 		      ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth));
143ab25eeb5Syz155240 	else
144ab25eeb5Syz155240 		return -1;
145ab25eeb5Syz155240 
146f4b3ec61Sdh155122 	KMALLOCS(ifs->ifs_fr_authpkts, mb_t **,
147f4b3ec61Sdh155122 		 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts));
148f4b3ec61Sdh155122 	if (ifs->ifs_fr_authpkts != NULL)
149f4b3ec61Sdh155122 		bzero((char *)ifs->ifs_fr_authpkts,
150f4b3ec61Sdh155122 		      ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts));
151ab25eeb5Syz155240 	else
152ab25eeb5Syz155240 		return -2;
153ab25eeb5Syz155240 
154f4b3ec61Sdh155122 	MUTEX_INIT(&ifs->ifs_ipf_authmx, "ipf auth log mutex");
155f4b3ec61Sdh155122 	RWLOCK_INIT(&ifs->ifs_ipf_auth, "ipf IP User-Auth rwlock");
156ab25eeb5Syz155240 #if SOLARIS && defined(_KERNEL)
157f4b3ec61Sdh155122 	cv_init(&ifs->ifs_ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL);
158ab25eeb5Syz155240 #endif
159ab25eeb5Syz155240 #if defined(linux) && defined(_KERNEL)
160ab25eeb5Syz155240 	init_waitqueue_head(&fr_authnext_linux);
161ab25eeb5Syz155240 #endif
162ab25eeb5Syz155240 
163f4b3ec61Sdh155122 	ifs->ifs_fr_auth_init = 1;
164ab25eeb5Syz155240 
165ab25eeb5Syz155240 	return 0;
166ab25eeb5Syz155240 }
167ab25eeb5Syz155240 
168ab25eeb5Syz155240 
169ab25eeb5Syz155240 /*
170ab25eeb5Syz155240  * Check if a packet has authorization.  If the packet is found to match an
171ab25eeb5Syz155240  * authorization result and that would result in a feedback loop (i.e. it
172ab25eeb5Syz155240  * will end up returning FR_AUTH) then return FR_BLOCK instead.
173ab25eeb5Syz155240  */
174ab25eeb5Syz155240 frentry_t *fr_checkauth(fin, passp)
175ab25eeb5Syz155240 fr_info_t *fin;
176ab25eeb5Syz155240 u_32_t *passp;
177ab25eeb5Syz155240 {
178ab25eeb5Syz155240 	frentry_t *fr;
179ab25eeb5Syz155240 	frauth_t *fra;
180ab25eeb5Syz155240 	u_32_t pass;
181ab25eeb5Syz155240 	u_short id;
182ab25eeb5Syz155240 	ip_t *ip;
183ab25eeb5Syz155240 	int i;
184f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
185ab25eeb5Syz155240 
186f4b3ec61Sdh155122 	if (ifs->ifs_fr_auth_lock || !ifs->ifs_fr_authused)
187ab25eeb5Syz155240 		return NULL;
188ab25eeb5Syz155240 
189ab25eeb5Syz155240 	ip = fin->fin_ip;
190ab25eeb5Syz155240 	id = ip->ip_id;
191ab25eeb5Syz155240 
192f4b3ec61Sdh155122 	READ_ENTER(&ifs->ifs_ipf_auth);
193f4b3ec61Sdh155122 	for (i = ifs->ifs_fr_authstart; i != ifs->ifs_fr_authend; ) {
194ab25eeb5Syz155240 		/*
195ab25eeb5Syz155240 		 * index becomes -2 only after an SIOCAUTHW.  Check this in
196ab25eeb5Syz155240 		 * case the same packet gets sent again and it hasn't yet been
197ab25eeb5Syz155240 		 * auth'd.
198ab25eeb5Syz155240 		 */
199f4b3ec61Sdh155122 		fra = ifs->ifs_fr_auth + i;
200ab25eeb5Syz155240 		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
201ab25eeb5Syz155240 		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
202ab25eeb5Syz155240 			/*
203ab25eeb5Syz155240 			 * Avoid feedback loop.
204ab25eeb5Syz155240 			 */
205ab25eeb5Syz155240 			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass)))
206ab25eeb5Syz155240 				pass = FR_BLOCK;
207ab25eeb5Syz155240 			/*
208ab25eeb5Syz155240 			 * Create a dummy rule for the stateful checking to
209ab25eeb5Syz155240 			 * use and return.  Zero out any values we don't
210ab25eeb5Syz155240 			 * trust from userland!
211ab25eeb5Syz155240 			 */
212ab25eeb5Syz155240 			if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
213ab25eeb5Syz155240 			     (fin->fin_flx & FI_FRAG))) {
214ab25eeb5Syz155240 				KMALLOC(fr, frentry_t *);
215ab25eeb5Syz155240 				if (fr) {
216ab25eeb5Syz155240 					bcopy((char *)fra->fra_info.fin_fr,
217ab25eeb5Syz155240 					      (char *)fr, sizeof(*fr));
218ab25eeb5Syz155240 					fr->fr_grp = NULL;
219ab25eeb5Syz155240 					fr->fr_ifa = fin->fin_ifp;
220ab25eeb5Syz155240 					fr->fr_func = NULL;
221ab25eeb5Syz155240 					fr->fr_ref = 1;
222ab25eeb5Syz155240 					fr->fr_flags = pass;
223ab25eeb5Syz155240 					fr->fr_ifas[1] = NULL;
224ab25eeb5Syz155240 					fr->fr_ifas[2] = NULL;
225ab25eeb5Syz155240 					fr->fr_ifas[3] = NULL;
226ab25eeb5Syz155240 				}
227ab25eeb5Syz155240 			} else
228ab25eeb5Syz155240 				fr = fra->fra_info.fin_fr;
229ab25eeb5Syz155240 			fin->fin_fr = fr;
230f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
231f4b3ec61Sdh155122 			WRITE_ENTER(&ifs->ifs_ipf_auth);
232ab25eeb5Syz155240 			if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
233f4b3ec61Sdh155122 				fr->fr_next = ifs->ifs_fr_authlist;
234f4b3ec61Sdh155122 				ifs->ifs_fr_authlist = fr;
235ab25eeb5Syz155240 			}
236f4b3ec61Sdh155122 			ifs->ifs_fr_authstats.fas_hits++;
237ab25eeb5Syz155240 			fra->fra_index = -1;
238f4b3ec61Sdh155122 			ifs->ifs_fr_authused--;
239f4b3ec61Sdh155122 			if (i == ifs->ifs_fr_authstart) {
240ab25eeb5Syz155240 				while (fra->fra_index == -1) {
241ab25eeb5Syz155240 					i++;
242ab25eeb5Syz155240 					fra++;
243f4b3ec61Sdh155122 					if (i == ifs->ifs_fr_authsize) {
244ab25eeb5Syz155240 						i = 0;
245f4b3ec61Sdh155122 						fra = ifs->ifs_fr_auth;
246ab25eeb5Syz155240 					}
247f4b3ec61Sdh155122 					ifs->ifs_fr_authstart = i;
248f4b3ec61Sdh155122 					if (i == ifs->ifs_fr_authend)
249ab25eeb5Syz155240 						break;
250ab25eeb5Syz155240 				}
251f4b3ec61Sdh155122 				if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) {
252f4b3ec61Sdh155122 					ifs->ifs_fr_authnext = 0;
253f4b3ec61Sdh155122 					ifs->ifs_fr_authstart = 0;
254f4b3ec61Sdh155122 					ifs->ifs_fr_authend = 0;
255ab25eeb5Syz155240 				}
256ab25eeb5Syz155240 			}
257f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
258ab25eeb5Syz155240 			if (passp != NULL)
259ab25eeb5Syz155240 				*passp = pass;
260f4b3ec61Sdh155122 			ATOMIC_INC64(ifs->ifs_fr_authstats.fas_hits);
261ab25eeb5Syz155240 			return fr;
262ab25eeb5Syz155240 		}
263ab25eeb5Syz155240 		i++;
264f4b3ec61Sdh155122 		if (i == ifs->ifs_fr_authsize)
265ab25eeb5Syz155240 			i = 0;
266ab25eeb5Syz155240 	}
267f4b3ec61Sdh155122 	ifs->ifs_fr_authstats.fas_miss++;
268f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
269f4b3ec61Sdh155122 	ATOMIC_INC64(ifs->ifs_fr_authstats.fas_miss);
270ab25eeb5Syz155240 	return NULL;
271ab25eeb5Syz155240 }
272ab25eeb5Syz155240 
273ab25eeb5Syz155240 
274ab25eeb5Syz155240 /*
275ab25eeb5Syz155240  * Check if we have room in the auth array to hold details for another packet.
276ab25eeb5Syz155240  * If we do, store it and wake up any user programs which are waiting to
277ab25eeb5Syz155240  * hear about these events.
278ab25eeb5Syz155240  */
279ab25eeb5Syz155240 int fr_newauth(m, fin)
280ab25eeb5Syz155240 mb_t *m;
281ab25eeb5Syz155240 fr_info_t *fin;
282ab25eeb5Syz155240 {
283ab25eeb5Syz155240 #if defined(_KERNEL) && defined(MENTAT)
284ab25eeb5Syz155240 	qpktinfo_t *qpi = fin->fin_qpi;
285ab25eeb5Syz155240 #endif
286ab25eeb5Syz155240 	frauth_t *fra;
287ab25eeb5Syz155240 #if !defined(sparc) && !defined(m68k)
288ab25eeb5Syz155240 	ip_t *ip;
289ab25eeb5Syz155240 #endif
290ab25eeb5Syz155240 	int i;
291f4b3ec61Sdh155122 	ipf_stack_t *ifs = fin->fin_ifs;
292ab25eeb5Syz155240 
293f4b3ec61Sdh155122 	if (ifs->ifs_fr_auth_lock)
294ab25eeb5Syz155240 		return 0;
295ab25eeb5Syz155240 
296f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_auth);
297f4b3ec61Sdh155122 	if (ifs->ifs_fr_authstart > ifs->ifs_fr_authend) {
298f4b3ec61Sdh155122 		ifs->ifs_fr_authstats.fas_nospace++;
299f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
300ab25eeb5Syz155240 		return 0;
301ab25eeb5Syz155240 	} else {
302f4b3ec61Sdh155122 		if (ifs->ifs_fr_authused == ifs->ifs_fr_authsize) {
303f4b3ec61Sdh155122 			ifs->ifs_fr_authstats.fas_nospace++;
304f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
305ab25eeb5Syz155240 			return 0;
306ab25eeb5Syz155240 		}
307ab25eeb5Syz155240 	}
308ab25eeb5Syz155240 
309f4b3ec61Sdh155122 	ifs->ifs_fr_authstats.fas_added++;
310f4b3ec61Sdh155122 	ifs->ifs_fr_authused++;
311f4b3ec61Sdh155122 	i = ifs->ifs_fr_authend++;
312f4b3ec61Sdh155122 	if (ifs->ifs_fr_authend == ifs->ifs_fr_authsize)
313f4b3ec61Sdh155122 		ifs->ifs_fr_authend = 0;
314f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
315ab25eeb5Syz155240 
316f4b3ec61Sdh155122 	fra = ifs->ifs_fr_auth + i;
317ab25eeb5Syz155240 	fra->fra_index = i;
318ab25eeb5Syz155240 	fra->fra_pass = 0;
319f4b3ec61Sdh155122 	fra->fra_age = ifs->ifs_fr_defaultauthage;
320ab25eeb5Syz155240 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
321ab25eeb5Syz155240 #if !defined(sparc) && !defined(m68k)
322ab25eeb5Syz155240 	/*
323ab25eeb5Syz155240 	 * No need to copyback here as we want to undo the changes, not keep
324ab25eeb5Syz155240 	 * them.
325ab25eeb5Syz155240 	 */
326ab25eeb5Syz155240 	ip = fin->fin_ip;
327ab25eeb5Syz155240 # if defined(MENTAT) && defined(_KERNEL)
328ab25eeb5Syz155240 	if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4))
329ab25eeb5Syz155240 # endif
330ab25eeb5Syz155240 	{
331ab25eeb5Syz155240 		register u_short bo;
332ab25eeb5Syz155240 
333ab25eeb5Syz155240 		bo = ip->ip_len;
334ab25eeb5Syz155240 		ip->ip_len = htons(bo);
335ab25eeb5Syz155240 		bo = ip->ip_off;
336ab25eeb5Syz155240 		ip->ip_off = htons(bo);
337ab25eeb5Syz155240 	}
338ab25eeb5Syz155240 #endif
339ab25eeb5Syz155240 #if SOLARIS && defined(_KERNEL)
340ab25eeb5Syz155240 	m->b_rptr -= qpi->qpi_off;
341f4b3ec61Sdh155122 	ifs->ifs_fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
342f4b3ec61Sdh155122 	cv_signal(&ifs->ifs_ipfauthwait);
343ab25eeb5Syz155240 #else
344ab25eeb5Syz155240 # if defined(BSD) && !defined(sparc) && (BSD >= 199306)
345ab25eeb5Syz155240 	if (!fin->fin_out) {
346ab25eeb5Syz155240 		ip->ip_len = htons(ip->ip_len);
347ab25eeb5Syz155240 		ip->ip_off = htons(ip->ip_off);
348ab25eeb5Syz155240 	}
349ab25eeb5Syz155240 # endif
350f4b3ec61Sdh155122 	ifs->ifs_fr_authpkts[i] = m;
351f4b3ec61Sdh155122 	WAKEUP(&ifs->ifs_fr_authnext, 0);
352ab25eeb5Syz155240 #endif
353ab25eeb5Syz155240 	return 1;
354ab25eeb5Syz155240 }
355ab25eeb5Syz155240 
356ab25eeb5Syz155240 
357f4b3ec61Sdh155122 int fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs)
358ab25eeb5Syz155240 caddr_t data;
359ab25eeb5Syz155240 ioctlcmd_t cmd;
360f4b3ec61Sdh155122 int mode,uid;
361f4b3ec61Sdh155122 void *ctx;
362f4b3ec61Sdh155122 ipf_stack_t *ifs;
363ab25eeb5Syz155240 {
364ab25eeb5Syz155240 	mb_t *m;
365ab25eeb5Syz155240 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \
366ab25eeb5Syz155240     (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000))
367ab25eeb5Syz155240 	struct ifqueue *ifq;
368ab25eeb5Syz155240 	SPL_INT(s);
369ab25eeb5Syz155240 #endif
370ab25eeb5Syz155240 	frauth_t auth, *au = &auth, *fra;
371ab25eeb5Syz155240 	int i, error = 0, len;
372ab25eeb5Syz155240 	char *t;
373381a2a9aSdr146992 	net_data_t net_data_p;
374381a2a9aSdr146992 	net_inject_t inj_data;
375381a2a9aSdr146992 	int ret;
376ab25eeb5Syz155240 
377ab25eeb5Syz155240 	switch (cmd)
378ab25eeb5Syz155240 	{
379f4b3ec61Sdh155122 	case SIOCGENITER :
380f4b3ec61Sdh155122 	    {
381f4b3ec61Sdh155122 		ipftoken_t *token;
382f4b3ec61Sdh155122 		ipfgeniter_t iter;
383f4b3ec61Sdh155122 
384f4b3ec61Sdh155122 		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
385f4b3ec61Sdh155122 		if (error != 0)
386f4b3ec61Sdh155122 			break;
387f4b3ec61Sdh155122 
388f4b3ec61Sdh155122 		token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx, ifs);
389f4b3ec61Sdh155122 		if (token != NULL)
390f4b3ec61Sdh155122 			error = fr_authgeniter(token, &iter, ifs);
391f4b3ec61Sdh155122 		else
392f4b3ec61Sdh155122 			error = ESRCH;
393f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_tokens);
394f4b3ec61Sdh155122 
395f4b3ec61Sdh155122 		break;
396f4b3ec61Sdh155122 	    }
397f4b3ec61Sdh155122 
398ab25eeb5Syz155240 	case SIOCSTLCK :
399ab25eeb5Syz155240 		if (!(mode & FWRITE)) {
400ab25eeb5Syz155240 			error = EPERM;
401ab25eeb5Syz155240 			break;
402ab25eeb5Syz155240 		}
403f4b3ec61Sdh155122 		fr_lock(data, &ifs->ifs_fr_auth_lock);
404ab25eeb5Syz155240 		break;
405ab25eeb5Syz155240 
406ab25eeb5Syz155240 	case SIOCATHST:
407f4b3ec61Sdh155122 		ifs->ifs_fr_authstats.fas_faelist = ifs->ifs_fae_list;
408f4b3ec61Sdh155122 		error = fr_outobj(data, &ifs->ifs_fr_authstats,
409f4b3ec61Sdh155122 		    IPFOBJ_AUTHSTAT);
410ab25eeb5Syz155240 		break;
411ab25eeb5Syz155240 
412ab25eeb5Syz155240 	case SIOCIPFFL:
413ab25eeb5Syz155240 		SPL_NET(s);
414f4b3ec61Sdh155122 		WRITE_ENTER(&ifs->ifs_ipf_auth);
415f4b3ec61Sdh155122 		i = fr_authflush(ifs);
416f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
417ab25eeb5Syz155240 		SPL_X(s);
418ab25eeb5Syz155240 		error = copyoutptr((char *)&i, data, sizeof(i));
419ab25eeb5Syz155240 		break;
420ab25eeb5Syz155240 
421ab25eeb5Syz155240 	case SIOCAUTHW:
422ab25eeb5Syz155240 fr_authioctlloop:
423ab25eeb5Syz155240 		error = fr_inobj(data, au, IPFOBJ_FRAUTH);
424f4b3ec61Sdh155122 		READ_ENTER(&ifs->ifs_ipf_auth);
425f4b3ec61Sdh155122 		if ((ifs->ifs_fr_authnext != ifs->ifs_fr_authend) &&
426f4b3ec61Sdh155122 		    ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]) {
427f4b3ec61Sdh155122 			error = fr_outobj(data,
428f4b3ec61Sdh155122 					  &ifs->ifs_fr_auth[ifs->ifs_fr_authnext],
429ab25eeb5Syz155240 					  IPFOBJ_FRAUTH);
430ab25eeb5Syz155240 			if (auth.fra_len != 0 && auth.fra_buf != NULL) {
431ab25eeb5Syz155240 				/*
432ab25eeb5Syz155240 				 * Copy packet contents out to user space if
433ab25eeb5Syz155240 				 * requested.  Bail on an error.
434ab25eeb5Syz155240 				 */
435f4b3ec61Sdh155122 				m = ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext];
436ab25eeb5Syz155240 				len = MSGDSIZE(m);
437ab25eeb5Syz155240 				if (len > auth.fra_len)
438ab25eeb5Syz155240 					len = auth.fra_len;
439ab25eeb5Syz155240 				auth.fra_len = len;
440ab25eeb5Syz155240 				for (t = auth.fra_buf; m && (len > 0); ) {
441ab25eeb5Syz155240 					i = MIN(M_LEN(m), len);
442ab25eeb5Syz155240 					error = copyoutptr(MTOD(m, char *),
443ab25eeb5Syz155240 							  t, i);
444ab25eeb5Syz155240 					len -= i;
445ab25eeb5Syz155240 					t += i;
446ab25eeb5Syz155240 					if (error != 0)
447ab25eeb5Syz155240 						break;
448ab25eeb5Syz155240 				}
449ab25eeb5Syz155240 			}
450f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
451ab25eeb5Syz155240 			if (error != 0)
452ab25eeb5Syz155240 				break;
453ab25eeb5Syz155240 			SPL_NET(s);
454f4b3ec61Sdh155122 			WRITE_ENTER(&ifs->ifs_ipf_auth);
455f4b3ec61Sdh155122 			ifs->ifs_fr_authnext++;
456f4b3ec61Sdh155122 			if (ifs->ifs_fr_authnext == ifs->ifs_fr_authsize)
457f4b3ec61Sdh155122 				ifs->ifs_fr_authnext = 0;
458f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
459ab25eeb5Syz155240 			SPL_X(s);
460ab25eeb5Syz155240 			return 0;
461ab25eeb5Syz155240 		}
462f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
463ab25eeb5Syz155240 		/*
464ab25eeb5Syz155240 		 * We exit ipf_global here because a program that enters in
465ab25eeb5Syz155240 		 * here will have a lock on it and goto sleep having this lock.
466ab25eeb5Syz155240 		 * If someone were to do an 'ipf -D' the system would then
467ab25eeb5Syz155240 		 * deadlock.  The catch with releasing it here is that the
468ab25eeb5Syz155240 		 * caller of this function expects it to be held when we
469ab25eeb5Syz155240 		 * return so we have to reacquire it in here.
470ab25eeb5Syz155240 		 */
471f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_global);
472ab25eeb5Syz155240 
473f4b3ec61Sdh155122 		MUTEX_ENTER(&ifs->ifs_ipf_authmx);
474ab25eeb5Syz155240 #ifdef	_KERNEL
475ab25eeb5Syz155240 # if	SOLARIS
476ab25eeb5Syz155240 		error = 0;
477f4b3ec61Sdh155122 		if (!cv_wait_sig(&ifs->ifs_ipfauthwait, &ifs->ifs_ipf_authmx.ipf_lk))
478ab25eeb5Syz155240 			error = EINTR;
479ab25eeb5Syz155240 # else /* SOLARIS */
480ab25eeb5Syz155240 #  ifdef __hpux
481ab25eeb5Syz155240 		{
482ab25eeb5Syz155240 		lock_t *l;
483ab25eeb5Syz155240 
484f4b3ec61Sdh155122 		l = get_sleep_lock(&ifs->ifs_fr_authnext);
485f4b3ec61Sdh155122 		error = sleep(&ifs->ifs_fr_authnext, PZERO+1);
486ab25eeb5Syz155240 		spinunlock(l);
487ab25eeb5Syz155240 		}
488ab25eeb5Syz155240 #  else
489ab25eeb5Syz155240 #   ifdef __osf__
490f4b3ec61Sdh155122 		error = mpsleep(&ifs->ifs_fr_authnext, PSUSP|PCATCH,
491f4b3ec61Sdh155122 				"fr_authnext", 0,
492f4b3ec61Sdh155122 				&ifs->ifs_ipf_authmx, MS_LOCK_SIMPLE);
493ab25eeb5Syz155240 #   else
494f4b3ec61Sdh155122 		error = SLEEP(&ifs->ifs_fr_authnext, "fr_authnext");
495ab25eeb5Syz155240 #   endif /* __osf__ */
496ab25eeb5Syz155240 #  endif /* __hpux */
497ab25eeb5Syz155240 # endif /* SOLARIS */
498ab25eeb5Syz155240 #endif
499f4b3ec61Sdh155122 		MUTEX_EXIT(&ifs->ifs_ipf_authmx);
500f4b3ec61Sdh155122 		READ_ENTER(&ifs->ifs_ipf_global);
501ab25eeb5Syz155240 		if (error == 0) {
502f4b3ec61Sdh155122 			READ_ENTER(&ifs->ifs_ipf_auth);
503ab25eeb5Syz155240 			goto fr_authioctlloop;
504ab25eeb5Syz155240 		}
505ab25eeb5Syz155240 		break;
506ab25eeb5Syz155240 
507ab25eeb5Syz155240 	case SIOCAUTHR:
508ab25eeb5Syz155240 		error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
509ab25eeb5Syz155240 		if (error != 0)
510ab25eeb5Syz155240 			return error;
511ab25eeb5Syz155240 		SPL_NET(s);
512f4b3ec61Sdh155122 		WRITE_ENTER(&ifs->ifs_ipf_auth);
513ab25eeb5Syz155240 		i = au->fra_index;
514f4b3ec61Sdh155122 		fra = ifs->ifs_fr_auth + i;
515f4b3ec61Sdh155122 		if ((i < 0) || (i >= ifs->ifs_fr_authsize) ||
516ab25eeb5Syz155240 		    (fra->fra_info.fin_id != au->fra_info.fin_id)) {
517f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
518ab25eeb5Syz155240 			SPL_X(s);
519ab25eeb5Syz155240 			return ESRCH;
520ab25eeb5Syz155240 		}
521f4b3ec61Sdh155122 		m = ifs->ifs_fr_authpkts[i];
522ab25eeb5Syz155240 		fra->fra_index = -2;
523ab25eeb5Syz155240 		fra->fra_pass = au->fra_pass;
524f4b3ec61Sdh155122 		ifs->ifs_fr_authpkts[i] = NULL;
525f4b3ec61Sdh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_auth);
526ab25eeb5Syz155240 #ifdef	_KERNEL
527381a2a9aSdr146992 		if (fra->fra_info.fin_v == 4) {
528f4b3ec61Sdh155122 			net_data_p = ifs->ifs_ipf_ipv4;
529381a2a9aSdr146992 		} else if (fra->fra_info.fin_v == 6) {
530f4b3ec61Sdh155122 			net_data_p = ifs->ifs_ipf_ipv6;
531381a2a9aSdr146992 		} else {
532381a2a9aSdr146992 			return (-1);
533381a2a9aSdr146992 		}
534381a2a9aSdr146992 
535381a2a9aSdr146992 		/*
536381a2a9aSdr146992 		 * We're putting the packet back on the same interface
537381a2a9aSdr146992 		 * queue that it was originally seen on so that it can
538381a2a9aSdr146992 		 * progress through the system properly, with the result
539381a2a9aSdr146992 		 * of the auth check done.
540381a2a9aSdr146992 		 */
541381a2a9aSdr146992 		inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp;
542381a2a9aSdr146992 
543ab25eeb5Syz155240 		if ((m != NULL) && (au->fra_info.fin_out != 0)) {
544ab25eeb5Syz155240 # ifdef MENTAT
545381a2a9aSdr146992 			inj_data.ni_packet = m;
546381a2a9aSdr146992 			ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data);
547381a2a9aSdr146992 
548381a2a9aSdr146992 			if (ret < 0)
549f4b3ec61Sdh155122 				ifs->ifs_fr_authstats.fas_sendfail++;
550381a2a9aSdr146992 			else
551f4b3ec61Sdh155122 				ifs->ifs_fr_authstats.fas_sendok++;
552ab25eeb5Syz155240 # else /* MENTAT */
553ab25eeb5Syz155240 #  if defined(linux) || defined(AIX)
554ab25eeb5Syz155240 #  else
555ab25eeb5Syz155240 #   if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \
556ab25eeb5Syz155240        (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \
557ab25eeb5Syz155240        (defined(__FreeBSD__) && (__FreeBSD_version >= 470102)))
558ab25eeb5Syz155240 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL,
559ab25eeb5Syz155240 					  NULL);
560ab25eeb5Syz155240 #   else
561ab25eeb5Syz155240 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
562ab25eeb5Syz155240 #   endif
563ab25eeb5Syz155240 			if (error != 0)
564f4b3ec61Sdh155122 				ifs->ifs_fr_authstats.fas_sendfail++;
565ab25eeb5Syz155240 			else
566f4b3ec61Sdh155122 				ifs->ifs_fr_authstats.fas_sendok++;
567381a2a9aSdr146992 #  endif /* Linux */
568381a2a9aSdr146992 # endif /* MENTAT */
569ab25eeb5Syz155240 		} else if (m) {
570ab25eeb5Syz155240 # ifdef MENTAT
571381a2a9aSdr146992 			inj_data.ni_packet = m;
572381a2a9aSdr146992 			ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data);
573ab25eeb5Syz155240 # else /* MENTAT */
574ab25eeb5Syz155240 #  if defined(linux) || defined(AIX)
575ab25eeb5Syz155240 #  else
576ab25eeb5Syz155240 #   if (__FreeBSD_version >= 501000)
577ab25eeb5Syz155240 			netisr_dispatch(NETISR_IP, m);
578ab25eeb5Syz155240 #   else
579ab25eeb5Syz155240 #    if (IRIX >= 60516)
580ab25eeb5Syz155240 			ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd;
581ab25eeb5Syz155240 #    else
582ab25eeb5Syz155240 			ifq = &ipintrq;
583ab25eeb5Syz155240 #    endif
584ab25eeb5Syz155240 			if (IF_QFULL(ifq)) {
585ab25eeb5Syz155240 				IF_DROP(ifq);
586ab25eeb5Syz155240 				FREE_MB_T(m);
587ab25eeb5Syz155240 				error = ENOBUFS;
588ab25eeb5Syz155240 			} else {
589ab25eeb5Syz155240 				IF_ENQUEUE(ifq, m);
590ab25eeb5Syz155240 #    if IRIX < 60500
591ab25eeb5Syz155240 				schednetisr(NETISR_IP);
592ab25eeb5Syz155240 #    endif
593ab25eeb5Syz155240 			}
594ab25eeb5Syz155240 #   endif
595ab25eeb5Syz155240 #  endif /* Linux */
596ab25eeb5Syz155240 # endif /* MENTAT */
597ab25eeb5Syz155240 			if (error != 0)
598f4b3ec61Sdh155122 				ifs->ifs_fr_authstats.fas_quefail++;
599ab25eeb5Syz155240 			else
600f4b3ec61Sdh155122 				ifs->ifs_fr_authstats.fas_queok++;
601ab25eeb5Syz155240 		} else
602ab25eeb5Syz155240 			error = EINVAL;
603ab25eeb5Syz155240 # ifdef MENTAT
604ab25eeb5Syz155240 		if (error != 0)
605ab25eeb5Syz155240 			error = EINVAL;
606ab25eeb5Syz155240 # else /* MENTAT */
607ab25eeb5Syz155240 		/*
608ab25eeb5Syz155240 		 * If we experience an error which will result in the packet
609ab25eeb5Syz155240 		 * not being processed, make sure we advance to the next one.
610ab25eeb5Syz155240 		 */
611ab25eeb5Syz155240 		if (error == ENOBUFS) {
612f4b3ec61Sdh155122 			ifs->ifs_fr_authused--;
613ab25eeb5Syz155240 			fra->fra_index = -1;
614ab25eeb5Syz155240 			fra->fra_pass = 0;
615f4b3ec61Sdh155122 			if (i == ifs->ifs_fr_authstart) {
616ab25eeb5Syz155240 				while (fra->fra_index == -1) {
617ab25eeb5Syz155240 					i++;
618f4b3ec61Sdh155122 					if (i == ifs->ifs_fr_authsize)
619ab25eeb5Syz155240 						i = 0;
620f4b3ec61Sdh155122 					ifs->ifs_fr_authstart = i;
621f4b3ec61Sdh155122 					if (i == ifs->ifs_fr_authend)
622ab25eeb5Syz155240 						break;
623ab25eeb5Syz155240 				}
624f4b3ec61Sdh155122 				if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) {
625f4b3ec61Sdh155122 					ifs->ifs_fr_authnext = 0;
626f4b3ec61Sdh155122 					ifs->ifs_fr_authstart = 0;
627f4b3ec61Sdh155122 					ifs->ifs_fr_authend = 0;
628ab25eeb5Syz155240 				}
629ab25eeb5Syz155240 			}
630ab25eeb5Syz155240 		}
631ab25eeb5Syz155240 # endif /* MENTAT */
632ab25eeb5Syz155240 #endif /* _KERNEL */
633ab25eeb5Syz155240 		SPL_X(s);
634ab25eeb5Syz155240 		break;
635ab25eeb5Syz155240 
636ab25eeb5Syz155240 	default :
637ab25eeb5Syz155240 		error = EINVAL;
638ab25eeb5Syz155240 		break;
639ab25eeb5Syz155240 	}
640ab25eeb5Syz155240 	return error;
641ab25eeb5Syz155240 }
642ab25eeb5Syz155240 
643ab25eeb5Syz155240 
644ab25eeb5Syz155240 /*
645ab25eeb5Syz155240  * Free all network buffer memory used to keep saved packets.
646ab25eeb5Syz155240  */
647f4b3ec61Sdh155122 void fr_authunload(ifs)
648f4b3ec61Sdh155122 ipf_stack_t *ifs;
649ab25eeb5Syz155240 {
650ab25eeb5Syz155240 	register int i;
651ab25eeb5Syz155240 	register frauthent_t *fae, **faep;
652ab25eeb5Syz155240 	frentry_t *fr, **frp;
653ab25eeb5Syz155240 	mb_t *m;
654ab25eeb5Syz155240 
655f4b3ec61Sdh155122 	if (ifs->ifs_fr_auth != NULL) {
656f4b3ec61Sdh155122 		KFREES(ifs->ifs_fr_auth,
657f4b3ec61Sdh155122 		       ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth));
658f4b3ec61Sdh155122 		ifs->ifs_fr_auth = NULL;
659ab25eeb5Syz155240 	}
660ab25eeb5Syz155240 
661f4b3ec61Sdh155122 	if (ifs->ifs_fr_authpkts != NULL) {
662f4b3ec61Sdh155122 		for (i = 0; i < ifs->ifs_fr_authsize; i++) {
663f4b3ec61Sdh155122 			m = ifs->ifs_fr_authpkts[i];
664ab25eeb5Syz155240 			if (m != NULL) {
665ab25eeb5Syz155240 				FREE_MB_T(m);
666f4b3ec61Sdh155122 				ifs->ifs_fr_authpkts[i] = NULL;
667ab25eeb5Syz155240 			}
668ab25eeb5Syz155240 		}
669f4b3ec61Sdh155122 		KFREES(ifs->ifs_fr_authpkts,
670f4b3ec61Sdh155122 		       ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts));
671f4b3ec61Sdh155122 		ifs->ifs_fr_authpkts = NULL;
672ab25eeb5Syz155240 	}
673ab25eeb5Syz155240 
674f4b3ec61Sdh155122 	faep = &ifs->ifs_fae_list;
675ab25eeb5Syz155240 	while ((fae = *faep) != NULL) {
676ab25eeb5Syz155240 		*faep = fae->fae_next;
677ab25eeb5Syz155240 		KFREE(fae);
678ab25eeb5Syz155240 	}
679f4b3ec61Sdh155122 	ifs->ifs_ipauth = NULL;
680ab25eeb5Syz155240 
681f4b3ec61Sdh155122 	if (ifs->ifs_fr_authlist != NULL) {
682f4b3ec61Sdh155122 		for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) {
683ab25eeb5Syz155240 			if (fr->fr_ref == 1) {
684ab25eeb5Syz155240 				*frp = fr->fr_next;
685ab25eeb5Syz155240 				KFREE(fr);
686ab25eeb5Syz155240 			} else
687ab25eeb5Syz155240 				frp = &fr->fr_next;
688ab25eeb5Syz155240 		}
689ab25eeb5Syz155240 	}
690ab25eeb5Syz155240 
691f4b3ec61Sdh155122 	if (ifs->ifs_fr_auth_init == 1) {
692ab25eeb5Syz155240 # if SOLARIS && defined(_KERNEL)
693f4b3ec61Sdh155122 		cv_destroy(&ifs->ifs_ipfauthwait);
694ab25eeb5Syz155240 # endif
695f4b3ec61Sdh155122 		MUTEX_DESTROY(&ifs->ifs_ipf_authmx);
696f4b3ec61Sdh155122 		RW_DESTROY(&ifs->ifs_ipf_auth);
697ab25eeb5Syz155240 
698f4b3ec61Sdh155122 		ifs->ifs_fr_auth_init = 0;
699ab25eeb5Syz155240 	}
700ab25eeb5Syz155240 }
701ab25eeb5Syz155240 
702ab25eeb5Syz155240 
703ab25eeb5Syz155240 /*
704ab25eeb5Syz155240  * Slowly expire held auth records.  Timeouts are set
705ab25eeb5Syz155240  * in expectation of this being called twice per second.
706ab25eeb5Syz155240  */
707f4b3ec61Sdh155122 void fr_authexpire(ifs)
708f4b3ec61Sdh155122 ipf_stack_t *ifs;
709ab25eeb5Syz155240 {
710ab25eeb5Syz155240 	register int i;
711ab25eeb5Syz155240 	register frauth_t *fra;
712ab25eeb5Syz155240 	register frauthent_t *fae, **faep;
713ab25eeb5Syz155240 	register frentry_t *fr, **frp;
714ab25eeb5Syz155240 	mb_t *m;
715ab25eeb5Syz155240 	SPL_INT(s);
716ab25eeb5Syz155240 
717f4b3ec61Sdh155122 	if (ifs->ifs_fr_auth_lock)
718ab25eeb5Syz155240 		return;
719ab25eeb5Syz155240 
720ab25eeb5Syz155240 	SPL_NET(s);
721f4b3ec61Sdh155122 	WRITE_ENTER(&ifs->ifs_ipf_auth);
722f4b3ec61Sdh155122 	for (i = 0, fra = ifs->ifs_fr_auth; i < ifs->ifs_fr_authsize; i++, fra++) {
723ab25eeb5Syz155240 		fra->fra_age--;
724f4b3ec61Sdh155122 		if ((fra->fra_age == 0) && (m = ifs->ifs_fr_authpkts[i])) {
725ab25eeb5Syz155240 			FREE_MB_T(m);
726f4b3ec61Sdh155122 			ifs->ifs_fr_authpkts[i] = NULL;
727f4b3ec61Sdh155122 			ifs->ifs_fr_auth[i].fra_index = -1;
728f4b3ec61Sdh155122 			ifs->ifs_fr_authstats.fas_expire++;
729f4b3ec61Sdh155122 			ifs->ifs_fr_authused--;
730ab25eeb5Syz155240 		}
731ab25eeb5Syz155240 	}
732ab25eeb5Syz155240 
733f4b3ec61Sdh155122 	for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) {
734ab25eeb5Syz155240 		fae->fae_age--;
735ab25eeb5Syz155240 		if (fae->fae_age == 0) {
736ab25eeb5Syz155240 			*faep = fae->fae_next;
737ab25eeb5Syz155240 			KFREE(fae);
738f4b3ec61Sdh155122 			ifs->ifs_fr_authstats.fas_expire++;
739ab25eeb5Syz155240 		} else
740ab25eeb5Syz155240 			faep = &fae->fae_next;
741ab25eeb5Syz155240 	}
742f4b3ec61Sdh155122 	if (ifs->ifs_fae_list != NULL)
743f4b3ec61Sdh155122 		ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr;
744ab25eeb5Syz155240 	else
745f4b3ec61Sdh155122 		ifs->ifs_ipauth = NULL;
746ab25eeb5Syz155240 
747f4b3ec61Sdh155122 	for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) {
748ab25eeb5Syz155240 		if (fr->fr_ref == 1) {
749ab25eeb5Syz155240 			*frp = fr->fr_next;
750ab25eeb5Syz155240 			KFREE(fr);
751ab25eeb5Syz155240 		} else
752ab25eeb5Syz155240 			frp = &fr->fr_next;
753ab25eeb5Syz155240 	}
754f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
755ab25eeb5Syz155240 	SPL_X(s);
756ab25eeb5Syz155240 }
757ab25eeb5Syz155240 
758f4b3ec61Sdh155122 int fr_preauthcmd(cmd, fr, frptr, ifs)
759ab25eeb5Syz155240 ioctlcmd_t cmd;
760ab25eeb5Syz155240 frentry_t *fr, **frptr;
761f4b3ec61Sdh155122 ipf_stack_t *ifs;
762ab25eeb5Syz155240 {
763ab25eeb5Syz155240 	frauthent_t *fae, **faep;
764ab25eeb5Syz155240 	int error = 0;
765ab25eeb5Syz155240 	SPL_INT(s);
766ab25eeb5Syz155240 
767ab25eeb5Syz155240 	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
768ab25eeb5Syz155240 		return EIO;
769ab25eeb5Syz155240 
770f4b3ec61Sdh155122 	for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) {
771ab25eeb5Syz155240 		if (&fae->fae_fr == fr)
772ab25eeb5Syz155240 			break;
773ab25eeb5Syz155240 		else
774ab25eeb5Syz155240 			faep = &fae->fae_next;
775ab25eeb5Syz155240 	}
776ab25eeb5Syz155240 
777ab25eeb5Syz155240 	if (cmd == (ioctlcmd_t)SIOCRMAFR) {
778ab25eeb5Syz155240 		if (fr == NULL || frptr == NULL)
779ab25eeb5Syz155240 			error = EINVAL;
780ab25eeb5Syz155240 		else if (fae == NULL)
781ab25eeb5Syz155240 			error = ESRCH;
782ab25eeb5Syz155240 		else {
783ab25eeb5Syz155240 			SPL_NET(s);
784f4b3ec61Sdh155122 			WRITE_ENTER(&ifs->ifs_ipf_auth);
785ab25eeb5Syz155240 			*faep = fae->fae_next;
786f4b3ec61Sdh155122 			if (ifs->ifs_ipauth == &fae->fae_fr)
787f4b3ec61Sdh155122 				ifs->ifs_ipauth = ifs->ifs_fae_list ?
788f4b3ec61Sdh155122 				    &ifs->ifs_fae_list->fae_fr : NULL;
789f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
790ab25eeb5Syz155240 			SPL_X(s);
791ab25eeb5Syz155240 
792ab25eeb5Syz155240 			KFREE(fae);
793ab25eeb5Syz155240 		}
794ab25eeb5Syz155240 	} else if (fr != NULL && frptr != NULL) {
795ab25eeb5Syz155240 		KMALLOC(fae, frauthent_t *);
796ab25eeb5Syz155240 		if (fae != NULL) {
797ab25eeb5Syz155240 			bcopy((char *)fr, (char *)&fae->fae_fr,
798ab25eeb5Syz155240 			      sizeof(*fr));
799ab25eeb5Syz155240 			SPL_NET(s);
800f4b3ec61Sdh155122 			WRITE_ENTER(&ifs->ifs_ipf_auth);
801f4b3ec61Sdh155122 			fae->fae_age = ifs->ifs_fr_defaultauthage;
802ab25eeb5Syz155240 			fae->fae_fr.fr_hits = 0;
803ab25eeb5Syz155240 			fae->fae_fr.fr_next = *frptr;
804f4b3ec61Sdh155122 			fae->fae_ref = 1;
805ab25eeb5Syz155240 			*frptr = &fae->fae_fr;
806ab25eeb5Syz155240 			fae->fae_next = *faep;
807ab25eeb5Syz155240 			*faep = fae;
808f4b3ec61Sdh155122 			ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr;
809f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
810ab25eeb5Syz155240 			SPL_X(s);
811ab25eeb5Syz155240 		} else
812ab25eeb5Syz155240 			error = ENOMEM;
813ab25eeb5Syz155240 	} else
814ab25eeb5Syz155240 		error = EINVAL;
815ab25eeb5Syz155240 	return error;
816ab25eeb5Syz155240 }
817ab25eeb5Syz155240 
818ab25eeb5Syz155240 
819ab25eeb5Syz155240 /*
820ab25eeb5Syz155240  * Flush held packets.
821ab25eeb5Syz155240  * Must already be properly SPL'ed and Locked on &ipf_auth.
822ab25eeb5Syz155240  *
823ab25eeb5Syz155240  */
824f4b3ec61Sdh155122 int fr_authflush(ifs)
825f4b3ec61Sdh155122 ipf_stack_t *ifs;
826ab25eeb5Syz155240 {
827ab25eeb5Syz155240 	register int i, num_flushed;
828ab25eeb5Syz155240 	mb_t *m;
829ab25eeb5Syz155240 
830f4b3ec61Sdh155122 	if (ifs->ifs_fr_auth_lock)
831ab25eeb5Syz155240 		return -1;
832ab25eeb5Syz155240 
833ab25eeb5Syz155240 	num_flushed = 0;
834ab25eeb5Syz155240 
835f4b3ec61Sdh155122 	for (i = 0 ; i < ifs->ifs_fr_authsize; i++) {
836f4b3ec61Sdh155122 		m = ifs->ifs_fr_authpkts[i];
837ab25eeb5Syz155240 		if (m != NULL) {
838ab25eeb5Syz155240 			FREE_MB_T(m);
839f4b3ec61Sdh155122 			ifs->ifs_fr_authpkts[i] = NULL;
840f4b3ec61Sdh155122 			ifs->ifs_fr_auth[i].fra_index = -1;
841ab25eeb5Syz155240 			/* perhaps add & use a flush counter inst.*/
842f4b3ec61Sdh155122 			ifs->ifs_fr_authstats.fas_expire++;
843f4b3ec61Sdh155122 			ifs->ifs_fr_authused--;
844ab25eeb5Syz155240 			num_flushed++;
845ab25eeb5Syz155240 		}
846ab25eeb5Syz155240 	}
847ab25eeb5Syz155240 
848f4b3ec61Sdh155122 	ifs->ifs_fr_authstart = 0;
849f4b3ec61Sdh155122 	ifs->ifs_fr_authend = 0;
850f4b3ec61Sdh155122 	ifs->ifs_fr_authnext = 0;
851ab25eeb5Syz155240 
852ab25eeb5Syz155240 	return num_flushed;
853ab25eeb5Syz155240 }
854f4b3ec61Sdh155122 
855f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */
856f4b3ec61Sdh155122 /* Function:    fr_authgeniter                                              */
857f4b3ec61Sdh155122 /* Returns:     int - 0 == success, else error                              */
858f4b3ec61Sdh155122 /* Parameters:  token(I) - pointer to ipftoken structure                    */
859f4b3ec61Sdh155122 /*              itp(I)   - pointer to ipfgeniter structure                  */
860f4b3ec61Sdh155122 /*                                                                          */
861f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */
862f4b3ec61Sdh155122 int fr_authgeniter(token, itp, ifs)
863f4b3ec61Sdh155122 ipftoken_t *token;
864f4b3ec61Sdh155122 ipfgeniter_t *itp;
865f4b3ec61Sdh155122 ipf_stack_t *ifs;
866f4b3ec61Sdh155122 {
867f4b3ec61Sdh155122 	frauthent_t *fae, *next, zero;
868f4b3ec61Sdh155122 	int error;
869f4b3ec61Sdh155122 
870f4b3ec61Sdh155122 	if (itp->igi_data == NULL)
871f4b3ec61Sdh155122 		return EFAULT;
872f4b3ec61Sdh155122 
873f4b3ec61Sdh155122 	if (itp->igi_type != IPFGENITER_AUTH)
874f4b3ec61Sdh155122 		return EINVAL;
875f4b3ec61Sdh155122 
876f4b3ec61Sdh155122 	READ_ENTER(&ifs->ifs_ipf_auth);
877*786c7074Sjojemann 
878*786c7074Sjojemann 	/*
879*786c7074Sjojemann 	 * Retrieve "previous" entry from token and find the next entry.
880*786c7074Sjojemann 	 */
881*786c7074Sjojemann 	fae = token->ipt_data;
882f4b3ec61Sdh155122 	if (fae == NULL) {
883f4b3ec61Sdh155122 		next = ifs->ifs_fae_list;
884f4b3ec61Sdh155122 	} else {
885f4b3ec61Sdh155122 		next = fae->fae_next;
886f4b3ec61Sdh155122 	}
887f4b3ec61Sdh155122 
888f4b3ec61Sdh155122 	/*
889*786c7074Sjojemann 	 * If we found an entry, add reference to it and update token.
890*786c7074Sjojemann 	 * Otherwise, zero out data to be returned and NULL out token.
891f4b3ec61Sdh155122 	 */
892*786c7074Sjojemann 	if (next != NULL) {
893f4b3ec61Sdh155122 		ATOMIC_INC(next->fae_ref);
894*786c7074Sjojemann 		token->ipt_data = next;
895f4b3ec61Sdh155122 	} else {
896f4b3ec61Sdh155122 		bzero(&zero, sizeof(zero));
897f4b3ec61Sdh155122 		next = &zero;
898*786c7074Sjojemann 		token->ipt_data = NULL;
899f4b3ec61Sdh155122 	}
900*786c7074Sjojemann 
901*786c7074Sjojemann 	/*
902*786c7074Sjojemann 	 * Safe to release the lock now that we have a reference.
903*786c7074Sjojemann 	 */
904f4b3ec61Sdh155122 	RWLOCK_EXIT(&ifs->ifs_ipf_auth);
905f4b3ec61Sdh155122 
906f4b3ec61Sdh155122 	/*
907*786c7074Sjojemann 	 * Copy out the data and clean up references and token as needed.
908f4b3ec61Sdh155122 	 */
909*786c7074Sjojemann 	error = COPYOUT(next, itp->igi_data, sizeof(*next));
910*786c7074Sjojemann 	if (error != 0)
911*786c7074Sjojemann 		error = EFAULT;
912*786c7074Sjojemann 	if (token->ipt_data == NULL) {
913*786c7074Sjojemann 		ipf_freetoken(token, ifs);
914*786c7074Sjojemann 	} else {
915f4b3ec61Sdh155122 		if (fae != NULL) {
916f4b3ec61Sdh155122 			WRITE_ENTER(&ifs->ifs_ipf_auth);
917f4b3ec61Sdh155122 			fr_authderef(&fae);
918f4b3ec61Sdh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_auth);
919f4b3ec61Sdh155122 		}
920*786c7074Sjojemann 		if (next->fae_next == NULL)
921*786c7074Sjojemann 			ipf_freetoken(token, ifs);
922*786c7074Sjojemann 	}
923f4b3ec61Sdh155122 	return error;
924f4b3ec61Sdh155122 }
925f4b3ec61Sdh155122 
926f4b3ec61Sdh155122 
927f4b3ec61Sdh155122 void fr_authderef(faep)
928f4b3ec61Sdh155122 frauthent_t **faep;
929f4b3ec61Sdh155122 {
930f4b3ec61Sdh155122 	frauthent_t *fae;
931f4b3ec61Sdh155122 
932f4b3ec61Sdh155122 	fae = *faep;
933f4b3ec61Sdh155122 	*faep = NULL;
934f4b3ec61Sdh155122 
935f4b3ec61Sdh155122 	fae->fae_ref--;
936f4b3ec61Sdh155122 	if (fae->fae_ref == 0) {
937f4b3ec61Sdh155122 		KFREE(fae);
938f4b3ec61Sdh155122 	}
939f4b3ec61Sdh155122 }
940