xref: /onnv-gate/usr/src/uts/common/inet/ipf/ip_auth.c (revision 2393:76e0289ce525)
1*2393Syz155240 /*
2*2393Syz155240  * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
3*2393Syz155240  *
4*2393Syz155240  * See the IPFILTER.LICENCE file for details on licencing.
5*2393Syz155240  */
6*2393Syz155240 #if defined(KERNEL) || defined(_KERNEL)
7*2393Syz155240 # undef KERNEL
8*2393Syz155240 # undef _KERNEL
9*2393Syz155240 # define        KERNEL	1
10*2393Syz155240 # define        _KERNEL	1
11*2393Syz155240 #endif
12*2393Syz155240 #include <sys/errno.h>
13*2393Syz155240 #include <sys/types.h>
14*2393Syz155240 #include <sys/param.h>
15*2393Syz155240 #include <sys/time.h>
16*2393Syz155240 #include <sys/file.h>
17*2393Syz155240 #if !defined(_KERNEL)
18*2393Syz155240 # include <stdio.h>
19*2393Syz155240 # include <stdlib.h>
20*2393Syz155240 # include <string.h>
21*2393Syz155240 # define _KERNEL
22*2393Syz155240 # ifdef __OpenBSD__
23*2393Syz155240 struct file;
24*2393Syz155240 # endif
25*2393Syz155240 # include <sys/uio.h>
26*2393Syz155240 # undef _KERNEL
27*2393Syz155240 #endif
28*2393Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
29*2393Syz155240 # include <sys/filio.h>
30*2393Syz155240 # include <sys/fcntl.h>
31*2393Syz155240 #else
32*2393Syz155240 # include <sys/ioctl.h>
33*2393Syz155240 #endif
34*2393Syz155240 #if !defined(linux)
35*2393Syz155240 # include <sys/protosw.h>
36*2393Syz155240 #endif
37*2393Syz155240 #include <sys/socket.h>
38*2393Syz155240 #if defined(_KERNEL)
39*2393Syz155240 # include <sys/systm.h>
40*2393Syz155240 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux)
41*2393Syz155240 #  include <sys/mbuf.h>
42*2393Syz155240 # endif
43*2393Syz155240 #endif
44*2393Syz155240 #if defined(__SVR4) || defined(__svr4__)
45*2393Syz155240 # include <sys/filio.h>
46*2393Syz155240 # include <sys/byteorder.h>
47*2393Syz155240 # ifdef _KERNEL
48*2393Syz155240 #  include <sys/dditypes.h>
49*2393Syz155240 # endif
50*2393Syz155240 # include <sys/stream.h>
51*2393Syz155240 # include <sys/kmem.h>
52*2393Syz155240 #endif
53*2393Syz155240 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000)
54*2393Syz155240 # include <sys/queue.h>
55*2393Syz155240 #endif
56*2393Syz155240 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
57*2393Syz155240 # include <machine/cpu.h>
58*2393Syz155240 #endif
59*2393Syz155240 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
60*2393Syz155240 # include <sys/proc.h>
61*2393Syz155240 #endif
62*2393Syz155240 #include <net/if.h>
63*2393Syz155240 #ifdef sun
64*2393Syz155240 # include <net/af.h>
65*2393Syz155240 #endif
66*2393Syz155240 #include <net/route.h>
67*2393Syz155240 #include <netinet/in.h>
68*2393Syz155240 #include <netinet/in_systm.h>
69*2393Syz155240 #include <netinet/ip.h>
70*2393Syz155240 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi)
71*2393Syz155240 # define	KERNEL
72*2393Syz155240 # define	_KERNEL
73*2393Syz155240 # define	NOT_KERNEL
74*2393Syz155240 #endif
75*2393Syz155240 #if !defined(linux)
76*2393Syz155240 # include <netinet/ip_var.h>
77*2393Syz155240 #endif
78*2393Syz155240 #ifdef	NOT_KERNEL
79*2393Syz155240 # undef	_KERNEL
80*2393Syz155240 # undef	KERNEL
81*2393Syz155240 #endif
82*2393Syz155240 #include <netinet/tcp.h>
83*2393Syz155240 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */
84*2393Syz155240 extern struct ifqueue   ipintrq;		/* ip packet input queue */
85*2393Syz155240 #else
86*2393Syz155240 # if !defined(__hpux) && !defined(linux)
87*2393Syz155240 #  if __FreeBSD_version >= 300000
88*2393Syz155240 #   include <net/if_var.h>
89*2393Syz155240 #   if __FreeBSD_version >= 500042
90*2393Syz155240 #    define IF_QFULL _IF_QFULL
91*2393Syz155240 #    define IF_DROP _IF_DROP
92*2393Syz155240 #   endif /* __FreeBSD_version >= 500042 */
93*2393Syz155240 #  endif
94*2393Syz155240 #  include <netinet/in_var.h>
95*2393Syz155240 #  include <netinet/tcp_fsm.h>
96*2393Syz155240 # endif
97*2393Syz155240 #endif
98*2393Syz155240 #include <netinet/udp.h>
99*2393Syz155240 #include <netinet/ip_icmp.h>
100*2393Syz155240 #include "netinet/ip_compat.h"
101*2393Syz155240 #include <netinet/tcpip.h>
102*2393Syz155240 #include "netinet/ip_fil.h"
103*2393Syz155240 #include "netinet/ip_auth.h"
104*2393Syz155240 #if !defined(MENTAT) && !defined(linux)
105*2393Syz155240 # include <net/netisr.h>
106*2393Syz155240 # ifdef __FreeBSD__
107*2393Syz155240 #  include <machine/cpufunc.h>
108*2393Syz155240 # endif
109*2393Syz155240 #endif
110*2393Syz155240 #if (__FreeBSD_version >= 300000)
111*2393Syz155240 # include <sys/malloc.h>
112*2393Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
113*2393Syz155240 #  include <sys/libkern.h>
114*2393Syz155240 #  include <sys/systm.h>
115*2393Syz155240 # endif
116*2393Syz155240 #endif
117*2393Syz155240 /* END OF INCLUDES */
118*2393Syz155240 
119*2393Syz155240 #if !defined(lint)
120*2393Syz155240 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $";
121*2393Syz155240 #endif
122*2393Syz155240 
123*2393Syz155240 
124*2393Syz155240 #if SOLARIS
125*2393Syz155240 extern kcondvar_t ipfauthwait;
126*2393Syz155240 #endif /* SOLARIS */
127*2393Syz155240 #if defined(linux) && defined(_KERNEL)
128*2393Syz155240 wait_queue_head_t     fr_authnext_linux;
129*2393Syz155240 #endif
130*2393Syz155240 
131*2393Syz155240 int	fr_authsize = FR_NUMAUTH;
132*2393Syz155240 int	fr_authused = 0;
133*2393Syz155240 int	fr_defaultauthage = 600;
134*2393Syz155240 int	fr_auth_lock = 0;
135*2393Syz155240 int	fr_auth_init = 0;
136*2393Syz155240 fr_authstat_t	fr_authstats;
137*2393Syz155240 static frauth_t *fr_auth = NULL;
138*2393Syz155240 mb_t	**fr_authpkts = NULL;
139*2393Syz155240 int	fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
140*2393Syz155240 frauthent_t	*fae_list = NULL;
141*2393Syz155240 frentry_t	*ipauth = NULL,
142*2393Syz155240 		*fr_authlist = NULL;
143*2393Syz155240 
144*2393Syz155240 
145*2393Syz155240 int fr_authinit()
146*2393Syz155240 {
147*2393Syz155240 	KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth));
148*2393Syz155240 	if (fr_auth != NULL)
149*2393Syz155240 		bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth));
150*2393Syz155240 	else
151*2393Syz155240 		return -1;
152*2393Syz155240 
153*2393Syz155240 	KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts));
154*2393Syz155240 	if (fr_authpkts != NULL)
155*2393Syz155240 		bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
156*2393Syz155240 	else
157*2393Syz155240 		return -2;
158*2393Syz155240 
159*2393Syz155240 	MUTEX_INIT(&ipf_authmx, "ipf auth log mutex");
160*2393Syz155240 	RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock");
161*2393Syz155240 #if SOLARIS && defined(_KERNEL)
162*2393Syz155240 	cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL);
163*2393Syz155240 #endif
164*2393Syz155240 #if defined(linux) && defined(_KERNEL)
165*2393Syz155240 	init_waitqueue_head(&fr_authnext_linux);
166*2393Syz155240 #endif
167*2393Syz155240 
168*2393Syz155240 	fr_auth_init = 1;
169*2393Syz155240 
170*2393Syz155240 	return 0;
171*2393Syz155240 }
172*2393Syz155240 
173*2393Syz155240 
174*2393Syz155240 /*
175*2393Syz155240  * Check if a packet has authorization.  If the packet is found to match an
176*2393Syz155240  * authorization result and that would result in a feedback loop (i.e. it
177*2393Syz155240  * will end up returning FR_AUTH) then return FR_BLOCK instead.
178*2393Syz155240  */
179*2393Syz155240 frentry_t *fr_checkauth(fin, passp)
180*2393Syz155240 fr_info_t *fin;
181*2393Syz155240 u_32_t *passp;
182*2393Syz155240 {
183*2393Syz155240 	frentry_t *fr;
184*2393Syz155240 	frauth_t *fra;
185*2393Syz155240 	u_32_t pass;
186*2393Syz155240 	u_short id;
187*2393Syz155240 	ip_t *ip;
188*2393Syz155240 	int i;
189*2393Syz155240 
190*2393Syz155240 	if (fr_auth_lock || !fr_authused)
191*2393Syz155240 		return NULL;
192*2393Syz155240 
193*2393Syz155240 	ip = fin->fin_ip;
194*2393Syz155240 	id = ip->ip_id;
195*2393Syz155240 
196*2393Syz155240 	READ_ENTER(&ipf_auth);
197*2393Syz155240 	for (i = fr_authstart; i != fr_authend; ) {
198*2393Syz155240 		/*
199*2393Syz155240 		 * index becomes -2 only after an SIOCAUTHW.  Check this in
200*2393Syz155240 		 * case the same packet gets sent again and it hasn't yet been
201*2393Syz155240 		 * auth'd.
202*2393Syz155240 		 */
203*2393Syz155240 		fra = fr_auth + i;
204*2393Syz155240 		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
205*2393Syz155240 		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
206*2393Syz155240 			/*
207*2393Syz155240 			 * Avoid feedback loop.
208*2393Syz155240 			 */
209*2393Syz155240 			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass)))
210*2393Syz155240 				pass = FR_BLOCK;
211*2393Syz155240 			/*
212*2393Syz155240 			 * Create a dummy rule for the stateful checking to
213*2393Syz155240 			 * use and return.  Zero out any values we don't
214*2393Syz155240 			 * trust from userland!
215*2393Syz155240 			 */
216*2393Syz155240 			if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
217*2393Syz155240 			     (fin->fin_flx & FI_FRAG))) {
218*2393Syz155240 				KMALLOC(fr, frentry_t *);
219*2393Syz155240 				if (fr) {
220*2393Syz155240 					bcopy((char *)fra->fra_info.fin_fr,
221*2393Syz155240 					      (char *)fr, sizeof(*fr));
222*2393Syz155240 					fr->fr_grp = NULL;
223*2393Syz155240 					fr->fr_ifa = fin->fin_ifp;
224*2393Syz155240 					fr->fr_func = NULL;
225*2393Syz155240 					fr->fr_ref = 1;
226*2393Syz155240 					fr->fr_flags = pass;
227*2393Syz155240 					fr->fr_ifas[1] = NULL;
228*2393Syz155240 					fr->fr_ifas[2] = NULL;
229*2393Syz155240 					fr->fr_ifas[3] = NULL;
230*2393Syz155240 				}
231*2393Syz155240 			} else
232*2393Syz155240 				fr = fra->fra_info.fin_fr;
233*2393Syz155240 			fin->fin_fr = fr;
234*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
235*2393Syz155240 			WRITE_ENTER(&ipf_auth);
236*2393Syz155240 			if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
237*2393Syz155240 				fr->fr_next = fr_authlist;
238*2393Syz155240 				fr_authlist = fr;
239*2393Syz155240 			}
240*2393Syz155240 			fr_authstats.fas_hits++;
241*2393Syz155240 			fra->fra_index = -1;
242*2393Syz155240 			fr_authused--;
243*2393Syz155240 			if (i == fr_authstart) {
244*2393Syz155240 				while (fra->fra_index == -1) {
245*2393Syz155240 					i++;
246*2393Syz155240 					fra++;
247*2393Syz155240 					if (i == fr_authsize) {
248*2393Syz155240 						i = 0;
249*2393Syz155240 						fra = fr_auth;
250*2393Syz155240 					}
251*2393Syz155240 					fr_authstart = i;
252*2393Syz155240 					if (i == fr_authend)
253*2393Syz155240 						break;
254*2393Syz155240 				}
255*2393Syz155240 				if (fr_authstart == fr_authend) {
256*2393Syz155240 					fr_authnext = 0;
257*2393Syz155240 					fr_authstart = fr_authend = 0;
258*2393Syz155240 				}
259*2393Syz155240 			}
260*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
261*2393Syz155240 			if (passp != NULL)
262*2393Syz155240 				*passp = pass;
263*2393Syz155240 			ATOMIC_INC64(fr_authstats.fas_hits);
264*2393Syz155240 			return fr;
265*2393Syz155240 		}
266*2393Syz155240 		i++;
267*2393Syz155240 		if (i == fr_authsize)
268*2393Syz155240 			i = 0;
269*2393Syz155240 	}
270*2393Syz155240 	fr_authstats.fas_miss++;
271*2393Syz155240 	RWLOCK_EXIT(&ipf_auth);
272*2393Syz155240 	ATOMIC_INC64(fr_authstats.fas_miss);
273*2393Syz155240 	return NULL;
274*2393Syz155240 }
275*2393Syz155240 
276*2393Syz155240 
277*2393Syz155240 /*
278*2393Syz155240  * Check if we have room in the auth array to hold details for another packet.
279*2393Syz155240  * If we do, store it and wake up any user programs which are waiting to
280*2393Syz155240  * hear about these events.
281*2393Syz155240  */
282*2393Syz155240 int fr_newauth(m, fin)
283*2393Syz155240 mb_t *m;
284*2393Syz155240 fr_info_t *fin;
285*2393Syz155240 {
286*2393Syz155240 #if defined(_KERNEL) && defined(MENTAT)
287*2393Syz155240 	qpktinfo_t *qpi = fin->fin_qpi;
288*2393Syz155240 #endif
289*2393Syz155240 	frauth_t *fra;
290*2393Syz155240 #if !defined(sparc) && !defined(m68k)
291*2393Syz155240 	ip_t *ip;
292*2393Syz155240 #endif
293*2393Syz155240 	int i;
294*2393Syz155240 
295*2393Syz155240 	if (fr_auth_lock)
296*2393Syz155240 		return 0;
297*2393Syz155240 
298*2393Syz155240 	WRITE_ENTER(&ipf_auth);
299*2393Syz155240 	if (fr_authstart > fr_authend) {
300*2393Syz155240 		fr_authstats.fas_nospace++;
301*2393Syz155240 		RWLOCK_EXIT(&ipf_auth);
302*2393Syz155240 		return 0;
303*2393Syz155240 	} else {
304*2393Syz155240 		if (fr_authused == fr_authsize) {
305*2393Syz155240 			fr_authstats.fas_nospace++;
306*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
307*2393Syz155240 			return 0;
308*2393Syz155240 		}
309*2393Syz155240 	}
310*2393Syz155240 
311*2393Syz155240 	fr_authstats.fas_added++;
312*2393Syz155240 	fr_authused++;
313*2393Syz155240 	i = fr_authend++;
314*2393Syz155240 	if (fr_authend == fr_authsize)
315*2393Syz155240 		fr_authend = 0;
316*2393Syz155240 	RWLOCK_EXIT(&ipf_auth);
317*2393Syz155240 
318*2393Syz155240 	fra = fr_auth + i;
319*2393Syz155240 	fra->fra_index = i;
320*2393Syz155240 	fra->fra_pass = 0;
321*2393Syz155240 	fra->fra_age = fr_defaultauthage;
322*2393Syz155240 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
323*2393Syz155240 #if !defined(sparc) && !defined(m68k)
324*2393Syz155240 	/*
325*2393Syz155240 	 * No need to copyback here as we want to undo the changes, not keep
326*2393Syz155240 	 * them.
327*2393Syz155240 	 */
328*2393Syz155240 	ip = fin->fin_ip;
329*2393Syz155240 # if defined(MENTAT) && defined(_KERNEL)
330*2393Syz155240 	if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4))
331*2393Syz155240 # endif
332*2393Syz155240 	{
333*2393Syz155240 		register u_short bo;
334*2393Syz155240 
335*2393Syz155240 		bo = ip->ip_len;
336*2393Syz155240 		ip->ip_len = htons(bo);
337*2393Syz155240 		bo = ip->ip_off;
338*2393Syz155240 		ip->ip_off = htons(bo);
339*2393Syz155240 	}
340*2393Syz155240 #endif
341*2393Syz155240 #if SOLARIS && defined(_KERNEL)
342*2393Syz155240 	m->b_rptr -= qpi->qpi_off;
343*2393Syz155240 	fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
344*2393Syz155240 	fra->fra_q = qpi->qpi_q;	/* The queue can disappear! */
345*2393Syz155240 	cv_signal(&ipfauthwait);
346*2393Syz155240 #else
347*2393Syz155240 # if defined(BSD) && !defined(sparc) && (BSD >= 199306)
348*2393Syz155240 	if (!fin->fin_out) {
349*2393Syz155240 		ip->ip_len = htons(ip->ip_len);
350*2393Syz155240 		ip->ip_off = htons(ip->ip_off);
351*2393Syz155240 	}
352*2393Syz155240 # endif
353*2393Syz155240 	fr_authpkts[i] = m;
354*2393Syz155240 	WAKEUP(&fr_authnext,0);
355*2393Syz155240 #endif
356*2393Syz155240 	return 1;
357*2393Syz155240 }
358*2393Syz155240 
359*2393Syz155240 
360*2393Syz155240 int fr_auth_ioctl(data, cmd, mode)
361*2393Syz155240 caddr_t data;
362*2393Syz155240 ioctlcmd_t cmd;
363*2393Syz155240 int mode;
364*2393Syz155240 {
365*2393Syz155240 	mb_t *m;
366*2393Syz155240 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \
367*2393Syz155240     (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000))
368*2393Syz155240 	struct ifqueue *ifq;
369*2393Syz155240 	SPL_INT(s);
370*2393Syz155240 #endif
371*2393Syz155240 	frauth_t auth, *au = &auth, *fra;
372*2393Syz155240 	int i, error = 0, len;
373*2393Syz155240 	char *t;
374*2393Syz155240 
375*2393Syz155240 	switch (cmd)
376*2393Syz155240 	{
377*2393Syz155240 	case SIOCSTLCK :
378*2393Syz155240 		if (!(mode & FWRITE)) {
379*2393Syz155240 			error = EPERM;
380*2393Syz155240 			break;
381*2393Syz155240 		}
382*2393Syz155240 		fr_lock(data, &fr_auth_lock);
383*2393Syz155240 		break;
384*2393Syz155240 
385*2393Syz155240 	case SIOCATHST:
386*2393Syz155240 		fr_authstats.fas_faelist = fae_list;
387*2393Syz155240 		error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT);
388*2393Syz155240 		break;
389*2393Syz155240 
390*2393Syz155240 	case SIOCIPFFL:
391*2393Syz155240 		SPL_NET(s);
392*2393Syz155240 		WRITE_ENTER(&ipf_auth);
393*2393Syz155240 		i = fr_authflush();
394*2393Syz155240 		RWLOCK_EXIT(&ipf_auth);
395*2393Syz155240 		SPL_X(s);
396*2393Syz155240 		error = copyoutptr((char *)&i, data, sizeof(i));
397*2393Syz155240 		break;
398*2393Syz155240 
399*2393Syz155240 	case SIOCAUTHW:
400*2393Syz155240 fr_authioctlloop:
401*2393Syz155240 		error = fr_inobj(data, au, IPFOBJ_FRAUTH);
402*2393Syz155240 		READ_ENTER(&ipf_auth);
403*2393Syz155240 		if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) {
404*2393Syz155240 			error = fr_outobj(data, &fr_auth[fr_authnext],
405*2393Syz155240 					  IPFOBJ_FRAUTH);
406*2393Syz155240 			if (auth.fra_len != 0 && auth.fra_buf != NULL) {
407*2393Syz155240 				/*
408*2393Syz155240 				 * Copy packet contents out to user space if
409*2393Syz155240 				 * requested.  Bail on an error.
410*2393Syz155240 				 */
411*2393Syz155240 				m = fr_authpkts[fr_authnext];
412*2393Syz155240 				len = MSGDSIZE(m);
413*2393Syz155240 				if (len > auth.fra_len)
414*2393Syz155240 					len = auth.fra_len;
415*2393Syz155240 				auth.fra_len = len;
416*2393Syz155240 				for (t = auth.fra_buf; m && (len > 0); ) {
417*2393Syz155240 					i = MIN(M_LEN(m), len);
418*2393Syz155240 					error = copyoutptr(MTOD(m, char *),
419*2393Syz155240 							  t, i);
420*2393Syz155240 					len -= i;
421*2393Syz155240 					t += i;
422*2393Syz155240 					if (error != 0)
423*2393Syz155240 						break;
424*2393Syz155240 				}
425*2393Syz155240 			}
426*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
427*2393Syz155240 			if (error != 0)
428*2393Syz155240 				break;
429*2393Syz155240 			SPL_NET(s);
430*2393Syz155240 			WRITE_ENTER(&ipf_auth);
431*2393Syz155240 			fr_authnext++;
432*2393Syz155240 			if (fr_authnext == fr_authsize)
433*2393Syz155240 				fr_authnext = 0;
434*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
435*2393Syz155240 			SPL_X(s);
436*2393Syz155240 			return 0;
437*2393Syz155240 		}
438*2393Syz155240 		RWLOCK_EXIT(&ipf_auth);
439*2393Syz155240 		/*
440*2393Syz155240 		 * We exit ipf_global here because a program that enters in
441*2393Syz155240 		 * here will have a lock on it and goto sleep having this lock.
442*2393Syz155240 		 * If someone were to do an 'ipf -D' the system would then
443*2393Syz155240 		 * deadlock.  The catch with releasing it here is that the
444*2393Syz155240 		 * caller of this function expects it to be held when we
445*2393Syz155240 		 * return so we have to reacquire it in here.
446*2393Syz155240 		 */
447*2393Syz155240 		RWLOCK_EXIT(&ipf_global);
448*2393Syz155240 
449*2393Syz155240 		MUTEX_ENTER(&ipf_authmx);
450*2393Syz155240 #ifdef	_KERNEL
451*2393Syz155240 # if	SOLARIS
452*2393Syz155240 		error = 0;
453*2393Syz155240 		if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk))
454*2393Syz155240 			error = EINTR;
455*2393Syz155240 # else /* SOLARIS */
456*2393Syz155240 #  ifdef __hpux
457*2393Syz155240 		{
458*2393Syz155240 		lock_t *l;
459*2393Syz155240 
460*2393Syz155240 		l = get_sleep_lock(&fr_authnext);
461*2393Syz155240 		error = sleep(&fr_authnext, PZERO+1);
462*2393Syz155240 		spinunlock(l);
463*2393Syz155240 		}
464*2393Syz155240 #  else
465*2393Syz155240 #   ifdef __osf__
466*2393Syz155240 		error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0,
467*2393Syz155240 				&ipf_authmx, MS_LOCK_SIMPLE);
468*2393Syz155240 #   else
469*2393Syz155240 		error = SLEEP(&fr_authnext, "fr_authnext");
470*2393Syz155240 #   endif /* __osf__ */
471*2393Syz155240 #  endif /* __hpux */
472*2393Syz155240 # endif /* SOLARIS */
473*2393Syz155240 #endif
474*2393Syz155240 		MUTEX_EXIT(&ipf_authmx);
475*2393Syz155240 		READ_ENTER(&ipf_global);
476*2393Syz155240 		if (error == 0) {
477*2393Syz155240 			READ_ENTER(&ipf_auth);
478*2393Syz155240 			goto fr_authioctlloop;
479*2393Syz155240 		}
480*2393Syz155240 		break;
481*2393Syz155240 
482*2393Syz155240 	case SIOCAUTHR:
483*2393Syz155240 		error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
484*2393Syz155240 		if (error != 0)
485*2393Syz155240 			return error;
486*2393Syz155240 		SPL_NET(s);
487*2393Syz155240 		WRITE_ENTER(&ipf_auth);
488*2393Syz155240 		i = au->fra_index;
489*2393Syz155240 		fra = fr_auth + i;
490*2393Syz155240 		if ((i < 0) || (i >= fr_authsize) ||
491*2393Syz155240 		    (fra->fra_info.fin_id != au->fra_info.fin_id)) {
492*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
493*2393Syz155240 			SPL_X(s);
494*2393Syz155240 			return ESRCH;
495*2393Syz155240 		}
496*2393Syz155240 		m = fr_authpkts[i];
497*2393Syz155240 		fra->fra_index = -2;
498*2393Syz155240 		fra->fra_pass = au->fra_pass;
499*2393Syz155240 		fr_authpkts[i] = NULL;
500*2393Syz155240 		RWLOCK_EXIT(&ipf_auth);
501*2393Syz155240 #ifdef	_KERNEL
502*2393Syz155240 		if ((m != NULL) && (au->fra_info.fin_out != 0)) {
503*2393Syz155240 # ifdef MENTAT
504*2393Syz155240 			error = !putq(fra->fra_q, m);
505*2393Syz155240 # else /* MENTAT */
506*2393Syz155240 #  if defined(linux) || defined(AIX)
507*2393Syz155240 #  else
508*2393Syz155240 #   if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \
509*2393Syz155240        (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \
510*2393Syz155240        (defined(__FreeBSD__) && (__FreeBSD_version >= 470102)))
511*2393Syz155240 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL,
512*2393Syz155240 					  NULL);
513*2393Syz155240 #   else
514*2393Syz155240 			error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
515*2393Syz155240 #   endif
516*2393Syz155240 #  endif /* Linux */
517*2393Syz155240 # endif /* MENTAT */
518*2393Syz155240 			if (error != 0)
519*2393Syz155240 				fr_authstats.fas_sendfail++;
520*2393Syz155240 			else
521*2393Syz155240 				fr_authstats.fas_sendok++;
522*2393Syz155240 		} else if (m) {
523*2393Syz155240 # ifdef MENTAT
524*2393Syz155240 			error = !putq(fra->fra_q, m);
525*2393Syz155240 # else /* MENTAT */
526*2393Syz155240 #  if defined(linux) || defined(AIX)
527*2393Syz155240 #  else
528*2393Syz155240 #   if (__FreeBSD_version >= 501000)
529*2393Syz155240 			netisr_dispatch(NETISR_IP, m);
530*2393Syz155240 #   else
531*2393Syz155240 #    if (IRIX >= 60516)
532*2393Syz155240 			ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd;
533*2393Syz155240 #    else
534*2393Syz155240 			ifq = &ipintrq;
535*2393Syz155240 #    endif
536*2393Syz155240 			if (IF_QFULL(ifq)) {
537*2393Syz155240 				IF_DROP(ifq);
538*2393Syz155240 				FREE_MB_T(m);
539*2393Syz155240 				error = ENOBUFS;
540*2393Syz155240 			} else {
541*2393Syz155240 				IF_ENQUEUE(ifq, m);
542*2393Syz155240 #    if IRIX < 60500
543*2393Syz155240 				schednetisr(NETISR_IP);
544*2393Syz155240 #    endif
545*2393Syz155240 			}
546*2393Syz155240 #   endif
547*2393Syz155240 #  endif /* Linux */
548*2393Syz155240 # endif /* MENTAT */
549*2393Syz155240 			if (error != 0)
550*2393Syz155240 				fr_authstats.fas_quefail++;
551*2393Syz155240 			else
552*2393Syz155240 				fr_authstats.fas_queok++;
553*2393Syz155240 		} else
554*2393Syz155240 			error = EINVAL;
555*2393Syz155240 # ifdef MENTAT
556*2393Syz155240 		if (error != 0)
557*2393Syz155240 			error = EINVAL;
558*2393Syz155240 # else /* MENTAT */
559*2393Syz155240 		/*
560*2393Syz155240 		 * If we experience an error which will result in the packet
561*2393Syz155240 		 * not being processed, make sure we advance to the next one.
562*2393Syz155240 		 */
563*2393Syz155240 		if (error == ENOBUFS) {
564*2393Syz155240 			fr_authused--;
565*2393Syz155240 			fra->fra_index = -1;
566*2393Syz155240 			fra->fra_pass = 0;
567*2393Syz155240 			if (i == fr_authstart) {
568*2393Syz155240 				while (fra->fra_index == -1) {
569*2393Syz155240 					i++;
570*2393Syz155240 					if (i == fr_authsize)
571*2393Syz155240 						i = 0;
572*2393Syz155240 					fr_authstart = i;
573*2393Syz155240 					if (i == fr_authend)
574*2393Syz155240 						break;
575*2393Syz155240 				}
576*2393Syz155240 				if (fr_authstart == fr_authend) {
577*2393Syz155240 					fr_authnext = 0;
578*2393Syz155240 					fr_authstart = fr_authend = 0;
579*2393Syz155240 				}
580*2393Syz155240 			}
581*2393Syz155240 		}
582*2393Syz155240 # endif /* MENTAT */
583*2393Syz155240 #endif /* _KERNEL */
584*2393Syz155240 		SPL_X(s);
585*2393Syz155240 		break;
586*2393Syz155240 
587*2393Syz155240 	default :
588*2393Syz155240 		error = EINVAL;
589*2393Syz155240 		break;
590*2393Syz155240 	}
591*2393Syz155240 	return error;
592*2393Syz155240 }
593*2393Syz155240 
594*2393Syz155240 
595*2393Syz155240 /*
596*2393Syz155240  * Free all network buffer memory used to keep saved packets.
597*2393Syz155240  */
598*2393Syz155240 void fr_authunload()
599*2393Syz155240 {
600*2393Syz155240 	register int i;
601*2393Syz155240 	register frauthent_t *fae, **faep;
602*2393Syz155240 	frentry_t *fr, **frp;
603*2393Syz155240 	mb_t *m;
604*2393Syz155240 
605*2393Syz155240 	if (fr_auth != NULL) {
606*2393Syz155240 		KFREES(fr_auth, fr_authsize * sizeof(*fr_auth));
607*2393Syz155240 		fr_auth = NULL;
608*2393Syz155240 	}
609*2393Syz155240 
610*2393Syz155240 	if (fr_authpkts != NULL) {
611*2393Syz155240 		for (i = 0; i < fr_authsize; i++) {
612*2393Syz155240 			m = fr_authpkts[i];
613*2393Syz155240 			if (m != NULL) {
614*2393Syz155240 				FREE_MB_T(m);
615*2393Syz155240 				fr_authpkts[i] = NULL;
616*2393Syz155240 			}
617*2393Syz155240 		}
618*2393Syz155240 		KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
619*2393Syz155240 		fr_authpkts = NULL;
620*2393Syz155240 	}
621*2393Syz155240 
622*2393Syz155240 	faep = &fae_list;
623*2393Syz155240 	while ((fae = *faep) != NULL) {
624*2393Syz155240 		*faep = fae->fae_next;
625*2393Syz155240 		KFREE(fae);
626*2393Syz155240 	}
627*2393Syz155240 	ipauth = NULL;
628*2393Syz155240 
629*2393Syz155240 	if (fr_authlist != NULL) {
630*2393Syz155240 		for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
631*2393Syz155240 			if (fr->fr_ref == 1) {
632*2393Syz155240 				*frp = fr->fr_next;
633*2393Syz155240 				KFREE(fr);
634*2393Syz155240 			} else
635*2393Syz155240 				frp = &fr->fr_next;
636*2393Syz155240 		}
637*2393Syz155240 	}
638*2393Syz155240 
639*2393Syz155240 	if (fr_auth_init == 1) {
640*2393Syz155240 # if SOLARIS && defined(_KERNEL)
641*2393Syz155240 		cv_destroy(&ipfauthwait);
642*2393Syz155240 # endif
643*2393Syz155240 		MUTEX_DESTROY(&ipf_authmx);
644*2393Syz155240 		RW_DESTROY(&ipf_auth);
645*2393Syz155240 
646*2393Syz155240 		fr_auth_init = 0;
647*2393Syz155240 	}
648*2393Syz155240 }
649*2393Syz155240 
650*2393Syz155240 
651*2393Syz155240 /*
652*2393Syz155240  * Slowly expire held auth records.  Timeouts are set
653*2393Syz155240  * in expectation of this being called twice per second.
654*2393Syz155240  */
655*2393Syz155240 void fr_authexpire()
656*2393Syz155240 {
657*2393Syz155240 	register int i;
658*2393Syz155240 	register frauth_t *fra;
659*2393Syz155240 	register frauthent_t *fae, **faep;
660*2393Syz155240 	register frentry_t *fr, **frp;
661*2393Syz155240 	mb_t *m;
662*2393Syz155240 	SPL_INT(s);
663*2393Syz155240 
664*2393Syz155240 	if (fr_auth_lock)
665*2393Syz155240 		return;
666*2393Syz155240 
667*2393Syz155240 	SPL_NET(s);
668*2393Syz155240 	WRITE_ENTER(&ipf_auth);
669*2393Syz155240 	for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) {
670*2393Syz155240 		fra->fra_age--;
671*2393Syz155240 		if ((fra->fra_age == 0) && (m = fr_authpkts[i])) {
672*2393Syz155240 			FREE_MB_T(m);
673*2393Syz155240 			fr_authpkts[i] = NULL;
674*2393Syz155240 			fr_auth[i].fra_index = -1;
675*2393Syz155240 			fr_authstats.fas_expire++;
676*2393Syz155240 			fr_authused--;
677*2393Syz155240 		}
678*2393Syz155240 	}
679*2393Syz155240 
680*2393Syz155240 	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
681*2393Syz155240 		fae->fae_age--;
682*2393Syz155240 		if (fae->fae_age == 0) {
683*2393Syz155240 			*faep = fae->fae_next;
684*2393Syz155240 			KFREE(fae);
685*2393Syz155240 			fr_authstats.fas_expire++;
686*2393Syz155240 		} else
687*2393Syz155240 			faep = &fae->fae_next;
688*2393Syz155240 	}
689*2393Syz155240 	if (fae_list != NULL)
690*2393Syz155240 		ipauth = &fae_list->fae_fr;
691*2393Syz155240 	else
692*2393Syz155240 		ipauth = NULL;
693*2393Syz155240 
694*2393Syz155240 	for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
695*2393Syz155240 		if (fr->fr_ref == 1) {
696*2393Syz155240 			*frp = fr->fr_next;
697*2393Syz155240 			KFREE(fr);
698*2393Syz155240 		} else
699*2393Syz155240 			frp = &fr->fr_next;
700*2393Syz155240 	}
701*2393Syz155240 	RWLOCK_EXIT(&ipf_auth);
702*2393Syz155240 	SPL_X(s);
703*2393Syz155240 }
704*2393Syz155240 
705*2393Syz155240 int fr_preauthcmd(cmd, fr, frptr)
706*2393Syz155240 ioctlcmd_t cmd;
707*2393Syz155240 frentry_t *fr, **frptr;
708*2393Syz155240 {
709*2393Syz155240 	frauthent_t *fae, **faep;
710*2393Syz155240 	int error = 0;
711*2393Syz155240 	SPL_INT(s);
712*2393Syz155240 
713*2393Syz155240 	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
714*2393Syz155240 		return EIO;
715*2393Syz155240 
716*2393Syz155240 	for (faep = &fae_list; ((fae = *faep) != NULL); ) {
717*2393Syz155240 		if (&fae->fae_fr == fr)
718*2393Syz155240 			break;
719*2393Syz155240 		else
720*2393Syz155240 			faep = &fae->fae_next;
721*2393Syz155240 	}
722*2393Syz155240 
723*2393Syz155240 	if (cmd == (ioctlcmd_t)SIOCRMAFR) {
724*2393Syz155240 		if (fr == NULL || frptr == NULL)
725*2393Syz155240 			error = EINVAL;
726*2393Syz155240 		else if (fae == NULL)
727*2393Syz155240 			error = ESRCH;
728*2393Syz155240 		else {
729*2393Syz155240 			SPL_NET(s);
730*2393Syz155240 			WRITE_ENTER(&ipf_auth);
731*2393Syz155240 			*faep = fae->fae_next;
732*2393Syz155240 			if (ipauth == &fae->fae_fr)
733*2393Syz155240 				ipauth = fae_list ? &fae_list->fae_fr : NULL;
734*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
735*2393Syz155240 			SPL_X(s);
736*2393Syz155240 
737*2393Syz155240 			KFREE(fae);
738*2393Syz155240 		}
739*2393Syz155240 	} else if (fr != NULL && frptr != NULL) {
740*2393Syz155240 		KMALLOC(fae, frauthent_t *);
741*2393Syz155240 		if (fae != NULL) {
742*2393Syz155240 			bcopy((char *)fr, (char *)&fae->fae_fr,
743*2393Syz155240 			      sizeof(*fr));
744*2393Syz155240 			SPL_NET(s);
745*2393Syz155240 			WRITE_ENTER(&ipf_auth);
746*2393Syz155240 			fae->fae_age = fr_defaultauthage;
747*2393Syz155240 			fae->fae_fr.fr_hits = 0;
748*2393Syz155240 			fae->fae_fr.fr_next = *frptr;
749*2393Syz155240 			*frptr = &fae->fae_fr;
750*2393Syz155240 			fae->fae_next = *faep;
751*2393Syz155240 			*faep = fae;
752*2393Syz155240 			ipauth = &fae_list->fae_fr;
753*2393Syz155240 			RWLOCK_EXIT(&ipf_auth);
754*2393Syz155240 			SPL_X(s);
755*2393Syz155240 		} else
756*2393Syz155240 			error = ENOMEM;
757*2393Syz155240 	} else
758*2393Syz155240 		error = EINVAL;
759*2393Syz155240 	return error;
760*2393Syz155240 }
761*2393Syz155240 
762*2393Syz155240 
763*2393Syz155240 /*
764*2393Syz155240  * Flush held packets.
765*2393Syz155240  * Must already be properly SPL'ed and Locked on &ipf_auth.
766*2393Syz155240  *
767*2393Syz155240  */
768*2393Syz155240 int fr_authflush()
769*2393Syz155240 {
770*2393Syz155240 	register int i, num_flushed;
771*2393Syz155240 	mb_t *m;
772*2393Syz155240 
773*2393Syz155240 	if (fr_auth_lock)
774*2393Syz155240 		return -1;
775*2393Syz155240 
776*2393Syz155240 	num_flushed = 0;
777*2393Syz155240 
778*2393Syz155240 	for (i = 0 ; i < fr_authsize; i++) {
779*2393Syz155240 		m = fr_authpkts[i];
780*2393Syz155240 		if (m != NULL) {
781*2393Syz155240 			FREE_MB_T(m);
782*2393Syz155240 			fr_authpkts[i] = NULL;
783*2393Syz155240 			fr_auth[i].fra_index = -1;
784*2393Syz155240 			/* perhaps add & use a flush counter inst.*/
785*2393Syz155240 			fr_authstats.fas_expire++;
786*2393Syz155240 			fr_authused--;
787*2393Syz155240 			num_flushed++;
788*2393Syz155240 		}
789*2393Syz155240 	}
790*2393Syz155240 
791*2393Syz155240 	fr_authstart = 0;
792*2393Syz155240 	fr_authend = 0;
793*2393Syz155240 	fr_authnext = 0;
794*2393Syz155240 
795*2393Syz155240 	return num_flushed;
796*2393Syz155240 }
797