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