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*f56257d8SToomas 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*f56257d8SToomas 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*f56257d8SToomas 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