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