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