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