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