12393Syz155240 /* 22393Syz155240 * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 32393Syz155240 * 42393Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 52393Syz155240 */ 6*2958Sdr146992 7*2958Sdr146992 /* 8*2958Sdr146992 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 9*2958Sdr146992 * Use is subject to license terms. 10*2958Sdr146992 */ 11*2958Sdr146992 12*2958Sdr146992 #pragma ident "%Z%%M% %I% %E% SMI" 13*2958Sdr146992 142393Syz155240 #if defined(KERNEL) || defined(_KERNEL) 152393Syz155240 # undef KERNEL 162393Syz155240 # undef _KERNEL 172393Syz155240 # define KERNEL 1 182393Syz155240 # define _KERNEL 1 192393Syz155240 #endif 202393Syz155240 #include <sys/errno.h> 212393Syz155240 #include <sys/types.h> 222393Syz155240 #include <sys/param.h> 232393Syz155240 #include <sys/time.h> 242393Syz155240 #include <sys/file.h> 252393Syz155240 #if !defined(_KERNEL) 262393Syz155240 # include <stdio.h> 272393Syz155240 # include <stdlib.h> 282393Syz155240 # include <string.h> 292393Syz155240 # define _KERNEL 302393Syz155240 # ifdef __OpenBSD__ 312393Syz155240 struct file; 322393Syz155240 # endif 332393Syz155240 # include <sys/uio.h> 342393Syz155240 # undef _KERNEL 352393Syz155240 #endif 362393Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 372393Syz155240 # include <sys/filio.h> 382393Syz155240 # include <sys/fcntl.h> 392393Syz155240 #else 402393Syz155240 # include <sys/ioctl.h> 412393Syz155240 #endif 422393Syz155240 #if !defined(linux) 432393Syz155240 # include <sys/protosw.h> 442393Syz155240 #endif 452393Syz155240 #include <sys/socket.h> 462393Syz155240 #if defined(_KERNEL) 472393Syz155240 # include <sys/systm.h> 482393Syz155240 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 492393Syz155240 # include <sys/mbuf.h> 502393Syz155240 # endif 512393Syz155240 #endif 522393Syz155240 #if defined(__SVR4) || defined(__svr4__) 532393Syz155240 # include <sys/filio.h> 542393Syz155240 # include <sys/byteorder.h> 552393Syz155240 # ifdef _KERNEL 562393Syz155240 # include <sys/dditypes.h> 572393Syz155240 # endif 582393Syz155240 # include <sys/stream.h> 592393Syz155240 # include <sys/kmem.h> 60*2958Sdr146992 # include <sys/neti.h> 612393Syz155240 #endif 622393Syz155240 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) 632393Syz155240 # include <sys/queue.h> 642393Syz155240 #endif 652393Syz155240 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 662393Syz155240 # include <machine/cpu.h> 672393Syz155240 #endif 682393Syz155240 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 692393Syz155240 # include <sys/proc.h> 702393Syz155240 #endif 712393Syz155240 #include <net/if.h> 722393Syz155240 #ifdef sun 732393Syz155240 # include <net/af.h> 742393Syz155240 #endif 752393Syz155240 #include <net/route.h> 762393Syz155240 #include <netinet/in.h> 772393Syz155240 #include <netinet/in_systm.h> 782393Syz155240 #include <netinet/ip.h> 792393Syz155240 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 802393Syz155240 # define KERNEL 812393Syz155240 # define _KERNEL 822393Syz155240 # define NOT_KERNEL 832393Syz155240 #endif 842393Syz155240 #if !defined(linux) 852393Syz155240 # include <netinet/ip_var.h> 862393Syz155240 #endif 872393Syz155240 #ifdef NOT_KERNEL 882393Syz155240 # undef _KERNEL 892393Syz155240 # undef KERNEL 902393Syz155240 #endif 912393Syz155240 #include <netinet/tcp.h> 922393Syz155240 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 932393Syz155240 extern struct ifqueue ipintrq; /* ip packet input queue */ 942393Syz155240 #else 952393Syz155240 # if !defined(__hpux) && !defined(linux) 962393Syz155240 # if __FreeBSD_version >= 300000 972393Syz155240 # include <net/if_var.h> 982393Syz155240 # if __FreeBSD_version >= 500042 992393Syz155240 # define IF_QFULL _IF_QFULL 1002393Syz155240 # define IF_DROP _IF_DROP 1012393Syz155240 # endif /* __FreeBSD_version >= 500042 */ 1022393Syz155240 # endif 1032393Syz155240 # include <netinet/in_var.h> 1042393Syz155240 # include <netinet/tcp_fsm.h> 1052393Syz155240 # endif 1062393Syz155240 #endif 1072393Syz155240 #include <netinet/udp.h> 1082393Syz155240 #include <netinet/ip_icmp.h> 1092393Syz155240 #include "netinet/ip_compat.h" 1102393Syz155240 #include <netinet/tcpip.h> 1112393Syz155240 #include "netinet/ip_fil.h" 1122393Syz155240 #include "netinet/ip_auth.h" 1132393Syz155240 #if !defined(MENTAT) && !defined(linux) 1142393Syz155240 # include <net/netisr.h> 1152393Syz155240 # ifdef __FreeBSD__ 1162393Syz155240 # include <machine/cpufunc.h> 1172393Syz155240 # endif 1182393Syz155240 #endif 1192393Syz155240 #if (__FreeBSD_version >= 300000) 1202393Syz155240 # include <sys/malloc.h> 1212393Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 1222393Syz155240 # include <sys/libkern.h> 1232393Syz155240 # include <sys/systm.h> 1242393Syz155240 # endif 1252393Syz155240 #endif 1262393Syz155240 /* END OF INCLUDES */ 1272393Syz155240 1282393Syz155240 #if !defined(lint) 1292393Syz155240 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $"; 1302393Syz155240 #endif 1312393Syz155240 1322393Syz155240 1332393Syz155240 #if SOLARIS 1342393Syz155240 extern kcondvar_t ipfauthwait; 1352393Syz155240 #endif /* SOLARIS */ 1362393Syz155240 #if defined(linux) && defined(_KERNEL) 1372393Syz155240 wait_queue_head_t fr_authnext_linux; 1382393Syz155240 #endif 1392393Syz155240 1402393Syz155240 int fr_authsize = FR_NUMAUTH; 1412393Syz155240 int fr_authused = 0; 1422393Syz155240 int fr_defaultauthage = 600; 1432393Syz155240 int fr_auth_lock = 0; 1442393Syz155240 int fr_auth_init = 0; 1452393Syz155240 fr_authstat_t fr_authstats; 1462393Syz155240 static frauth_t *fr_auth = NULL; 1472393Syz155240 mb_t **fr_authpkts = NULL; 1482393Syz155240 int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; 1492393Syz155240 frauthent_t *fae_list = NULL; 1502393Syz155240 frentry_t *ipauth = NULL, 1512393Syz155240 *fr_authlist = NULL; 1522393Syz155240 153*2958Sdr146992 #if SOLARIS2 >= 10 154*2958Sdr146992 extern net_data_t ipf_ipv4; 155*2958Sdr146992 extern net_data_t ipf_ipv6; 156*2958Sdr146992 #endif 1572393Syz155240 1582393Syz155240 int fr_authinit() 1592393Syz155240 { 1602393Syz155240 KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); 1612393Syz155240 if (fr_auth != NULL) 1622393Syz155240 bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); 1632393Syz155240 else 1642393Syz155240 return -1; 1652393Syz155240 1662393Syz155240 KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); 1672393Syz155240 if (fr_authpkts != NULL) 1682393Syz155240 bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 1692393Syz155240 else 1702393Syz155240 return -2; 1712393Syz155240 1722393Syz155240 MUTEX_INIT(&ipf_authmx, "ipf auth log mutex"); 1732393Syz155240 RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock"); 1742393Syz155240 #if SOLARIS && defined(_KERNEL) 1752393Syz155240 cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 1762393Syz155240 #endif 1772393Syz155240 #if defined(linux) && defined(_KERNEL) 1782393Syz155240 init_waitqueue_head(&fr_authnext_linux); 1792393Syz155240 #endif 1802393Syz155240 1812393Syz155240 fr_auth_init = 1; 1822393Syz155240 1832393Syz155240 return 0; 1842393Syz155240 } 1852393Syz155240 1862393Syz155240 1872393Syz155240 /* 1882393Syz155240 * Check if a packet has authorization. If the packet is found to match an 1892393Syz155240 * authorization result and that would result in a feedback loop (i.e. it 1902393Syz155240 * will end up returning FR_AUTH) then return FR_BLOCK instead. 1912393Syz155240 */ 1922393Syz155240 frentry_t *fr_checkauth(fin, passp) 1932393Syz155240 fr_info_t *fin; 1942393Syz155240 u_32_t *passp; 1952393Syz155240 { 1962393Syz155240 frentry_t *fr; 1972393Syz155240 frauth_t *fra; 1982393Syz155240 u_32_t pass; 1992393Syz155240 u_short id; 2002393Syz155240 ip_t *ip; 2012393Syz155240 int i; 2022393Syz155240 2032393Syz155240 if (fr_auth_lock || !fr_authused) 2042393Syz155240 return NULL; 2052393Syz155240 2062393Syz155240 ip = fin->fin_ip; 2072393Syz155240 id = ip->ip_id; 2082393Syz155240 2092393Syz155240 READ_ENTER(&ipf_auth); 2102393Syz155240 for (i = fr_authstart; i != fr_authend; ) { 2112393Syz155240 /* 2122393Syz155240 * index becomes -2 only after an SIOCAUTHW. Check this in 2132393Syz155240 * case the same packet gets sent again and it hasn't yet been 2142393Syz155240 * auth'd. 2152393Syz155240 */ 2162393Syz155240 fra = fr_auth + i; 2172393Syz155240 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 2182393Syz155240 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 2192393Syz155240 /* 2202393Syz155240 * Avoid feedback loop. 2212393Syz155240 */ 2222393Syz155240 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 2232393Syz155240 pass = FR_BLOCK; 2242393Syz155240 /* 2252393Syz155240 * Create a dummy rule for the stateful checking to 2262393Syz155240 * use and return. Zero out any values we don't 2272393Syz155240 * trust from userland! 2282393Syz155240 */ 2292393Syz155240 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 2302393Syz155240 (fin->fin_flx & FI_FRAG))) { 2312393Syz155240 KMALLOC(fr, frentry_t *); 2322393Syz155240 if (fr) { 2332393Syz155240 bcopy((char *)fra->fra_info.fin_fr, 2342393Syz155240 (char *)fr, sizeof(*fr)); 2352393Syz155240 fr->fr_grp = NULL; 2362393Syz155240 fr->fr_ifa = fin->fin_ifp; 2372393Syz155240 fr->fr_func = NULL; 2382393Syz155240 fr->fr_ref = 1; 2392393Syz155240 fr->fr_flags = pass; 2402393Syz155240 fr->fr_ifas[1] = NULL; 2412393Syz155240 fr->fr_ifas[2] = NULL; 2422393Syz155240 fr->fr_ifas[3] = NULL; 2432393Syz155240 } 2442393Syz155240 } else 2452393Syz155240 fr = fra->fra_info.fin_fr; 2462393Syz155240 fin->fin_fr = fr; 2472393Syz155240 RWLOCK_EXIT(&ipf_auth); 2482393Syz155240 WRITE_ENTER(&ipf_auth); 2492393Syz155240 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 2502393Syz155240 fr->fr_next = fr_authlist; 2512393Syz155240 fr_authlist = fr; 2522393Syz155240 } 2532393Syz155240 fr_authstats.fas_hits++; 2542393Syz155240 fra->fra_index = -1; 2552393Syz155240 fr_authused--; 2562393Syz155240 if (i == fr_authstart) { 2572393Syz155240 while (fra->fra_index == -1) { 2582393Syz155240 i++; 2592393Syz155240 fra++; 2602393Syz155240 if (i == fr_authsize) { 2612393Syz155240 i = 0; 2622393Syz155240 fra = fr_auth; 2632393Syz155240 } 2642393Syz155240 fr_authstart = i; 2652393Syz155240 if (i == fr_authend) 2662393Syz155240 break; 2672393Syz155240 } 2682393Syz155240 if (fr_authstart == fr_authend) { 2692393Syz155240 fr_authnext = 0; 2702393Syz155240 fr_authstart = fr_authend = 0; 2712393Syz155240 } 2722393Syz155240 } 2732393Syz155240 RWLOCK_EXIT(&ipf_auth); 2742393Syz155240 if (passp != NULL) 2752393Syz155240 *passp = pass; 2762393Syz155240 ATOMIC_INC64(fr_authstats.fas_hits); 2772393Syz155240 return fr; 2782393Syz155240 } 2792393Syz155240 i++; 2802393Syz155240 if (i == fr_authsize) 2812393Syz155240 i = 0; 2822393Syz155240 } 2832393Syz155240 fr_authstats.fas_miss++; 2842393Syz155240 RWLOCK_EXIT(&ipf_auth); 2852393Syz155240 ATOMIC_INC64(fr_authstats.fas_miss); 2862393Syz155240 return NULL; 2872393Syz155240 } 2882393Syz155240 2892393Syz155240 2902393Syz155240 /* 2912393Syz155240 * Check if we have room in the auth array to hold details for another packet. 2922393Syz155240 * If we do, store it and wake up any user programs which are waiting to 2932393Syz155240 * hear about these events. 2942393Syz155240 */ 2952393Syz155240 int fr_newauth(m, fin) 2962393Syz155240 mb_t *m; 2972393Syz155240 fr_info_t *fin; 2982393Syz155240 { 2992393Syz155240 #if defined(_KERNEL) && defined(MENTAT) 3002393Syz155240 qpktinfo_t *qpi = fin->fin_qpi; 3012393Syz155240 #endif 3022393Syz155240 frauth_t *fra; 3032393Syz155240 #if !defined(sparc) && !defined(m68k) 3042393Syz155240 ip_t *ip; 3052393Syz155240 #endif 3062393Syz155240 int i; 3072393Syz155240 3082393Syz155240 if (fr_auth_lock) 3092393Syz155240 return 0; 3102393Syz155240 3112393Syz155240 WRITE_ENTER(&ipf_auth); 3122393Syz155240 if (fr_authstart > fr_authend) { 3132393Syz155240 fr_authstats.fas_nospace++; 3142393Syz155240 RWLOCK_EXIT(&ipf_auth); 3152393Syz155240 return 0; 3162393Syz155240 } else { 3172393Syz155240 if (fr_authused == fr_authsize) { 3182393Syz155240 fr_authstats.fas_nospace++; 3192393Syz155240 RWLOCK_EXIT(&ipf_auth); 3202393Syz155240 return 0; 3212393Syz155240 } 3222393Syz155240 } 3232393Syz155240 3242393Syz155240 fr_authstats.fas_added++; 3252393Syz155240 fr_authused++; 3262393Syz155240 i = fr_authend++; 3272393Syz155240 if (fr_authend == fr_authsize) 3282393Syz155240 fr_authend = 0; 3292393Syz155240 RWLOCK_EXIT(&ipf_auth); 3302393Syz155240 3312393Syz155240 fra = fr_auth + i; 3322393Syz155240 fra->fra_index = i; 3332393Syz155240 fra->fra_pass = 0; 3342393Syz155240 fra->fra_age = fr_defaultauthage; 3352393Syz155240 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 3362393Syz155240 #if !defined(sparc) && !defined(m68k) 3372393Syz155240 /* 3382393Syz155240 * No need to copyback here as we want to undo the changes, not keep 3392393Syz155240 * them. 3402393Syz155240 */ 3412393Syz155240 ip = fin->fin_ip; 3422393Syz155240 # if defined(MENTAT) && defined(_KERNEL) 3432393Syz155240 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 3442393Syz155240 # endif 3452393Syz155240 { 3462393Syz155240 register u_short bo; 3472393Syz155240 3482393Syz155240 bo = ip->ip_len; 3492393Syz155240 ip->ip_len = htons(bo); 3502393Syz155240 bo = ip->ip_off; 3512393Syz155240 ip->ip_off = htons(bo); 3522393Syz155240 } 3532393Syz155240 #endif 3542393Syz155240 #if SOLARIS && defined(_KERNEL) 3552393Syz155240 m->b_rptr -= qpi->qpi_off; 3562393Syz155240 fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 3572393Syz155240 cv_signal(&ipfauthwait); 3582393Syz155240 #else 3592393Syz155240 # if defined(BSD) && !defined(sparc) && (BSD >= 199306) 3602393Syz155240 if (!fin->fin_out) { 3612393Syz155240 ip->ip_len = htons(ip->ip_len); 3622393Syz155240 ip->ip_off = htons(ip->ip_off); 3632393Syz155240 } 3642393Syz155240 # endif 3652393Syz155240 fr_authpkts[i] = m; 3662393Syz155240 WAKEUP(&fr_authnext,0); 3672393Syz155240 #endif 3682393Syz155240 return 1; 3692393Syz155240 } 3702393Syz155240 3712393Syz155240 3722393Syz155240 int fr_auth_ioctl(data, cmd, mode) 3732393Syz155240 caddr_t data; 3742393Syz155240 ioctlcmd_t cmd; 3752393Syz155240 int mode; 3762393Syz155240 { 3772393Syz155240 mb_t *m; 3782393Syz155240 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 3792393Syz155240 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 3802393Syz155240 struct ifqueue *ifq; 3812393Syz155240 SPL_INT(s); 3822393Syz155240 #endif 3832393Syz155240 frauth_t auth, *au = &auth, *fra; 3842393Syz155240 int i, error = 0, len; 3852393Syz155240 char *t; 386*2958Sdr146992 net_data_t net_data_p; 387*2958Sdr146992 net_inject_t inj_data; 388*2958Sdr146992 int ret; 3892393Syz155240 3902393Syz155240 switch (cmd) 3912393Syz155240 { 3922393Syz155240 case SIOCSTLCK : 3932393Syz155240 if (!(mode & FWRITE)) { 3942393Syz155240 error = EPERM; 3952393Syz155240 break; 3962393Syz155240 } 3972393Syz155240 fr_lock(data, &fr_auth_lock); 3982393Syz155240 break; 3992393Syz155240 4002393Syz155240 case SIOCATHST: 4012393Syz155240 fr_authstats.fas_faelist = fae_list; 4022393Syz155240 error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); 4032393Syz155240 break; 4042393Syz155240 4052393Syz155240 case SIOCIPFFL: 4062393Syz155240 SPL_NET(s); 4072393Syz155240 WRITE_ENTER(&ipf_auth); 4082393Syz155240 i = fr_authflush(); 4092393Syz155240 RWLOCK_EXIT(&ipf_auth); 4102393Syz155240 SPL_X(s); 4112393Syz155240 error = copyoutptr((char *)&i, data, sizeof(i)); 4122393Syz155240 break; 4132393Syz155240 4142393Syz155240 case SIOCAUTHW: 4152393Syz155240 fr_authioctlloop: 4162393Syz155240 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 4172393Syz155240 READ_ENTER(&ipf_auth); 4182393Syz155240 if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { 4192393Syz155240 error = fr_outobj(data, &fr_auth[fr_authnext], 4202393Syz155240 IPFOBJ_FRAUTH); 4212393Syz155240 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 4222393Syz155240 /* 4232393Syz155240 * Copy packet contents out to user space if 4242393Syz155240 * requested. Bail on an error. 4252393Syz155240 */ 4262393Syz155240 m = fr_authpkts[fr_authnext]; 4272393Syz155240 len = MSGDSIZE(m); 4282393Syz155240 if (len > auth.fra_len) 4292393Syz155240 len = auth.fra_len; 4302393Syz155240 auth.fra_len = len; 4312393Syz155240 for (t = auth.fra_buf; m && (len > 0); ) { 4322393Syz155240 i = MIN(M_LEN(m), len); 4332393Syz155240 error = copyoutptr(MTOD(m, char *), 4342393Syz155240 t, i); 4352393Syz155240 len -= i; 4362393Syz155240 t += i; 4372393Syz155240 if (error != 0) 4382393Syz155240 break; 4392393Syz155240 } 4402393Syz155240 } 4412393Syz155240 RWLOCK_EXIT(&ipf_auth); 4422393Syz155240 if (error != 0) 4432393Syz155240 break; 4442393Syz155240 SPL_NET(s); 4452393Syz155240 WRITE_ENTER(&ipf_auth); 4462393Syz155240 fr_authnext++; 4472393Syz155240 if (fr_authnext == fr_authsize) 4482393Syz155240 fr_authnext = 0; 4492393Syz155240 RWLOCK_EXIT(&ipf_auth); 4502393Syz155240 SPL_X(s); 4512393Syz155240 return 0; 4522393Syz155240 } 4532393Syz155240 RWLOCK_EXIT(&ipf_auth); 4542393Syz155240 /* 4552393Syz155240 * We exit ipf_global here because a program that enters in 4562393Syz155240 * here will have a lock on it and goto sleep having this lock. 4572393Syz155240 * If someone were to do an 'ipf -D' the system would then 4582393Syz155240 * deadlock. The catch with releasing it here is that the 4592393Syz155240 * caller of this function expects it to be held when we 4602393Syz155240 * return so we have to reacquire it in here. 4612393Syz155240 */ 4622393Syz155240 RWLOCK_EXIT(&ipf_global); 4632393Syz155240 4642393Syz155240 MUTEX_ENTER(&ipf_authmx); 4652393Syz155240 #ifdef _KERNEL 4662393Syz155240 # if SOLARIS 4672393Syz155240 error = 0; 4682393Syz155240 if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) 4692393Syz155240 error = EINTR; 4702393Syz155240 # else /* SOLARIS */ 4712393Syz155240 # ifdef __hpux 4722393Syz155240 { 4732393Syz155240 lock_t *l; 4742393Syz155240 4752393Syz155240 l = get_sleep_lock(&fr_authnext); 4762393Syz155240 error = sleep(&fr_authnext, PZERO+1); 4772393Syz155240 spinunlock(l); 4782393Syz155240 } 4792393Syz155240 # else 4802393Syz155240 # ifdef __osf__ 4812393Syz155240 error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, 4822393Syz155240 &ipf_authmx, MS_LOCK_SIMPLE); 4832393Syz155240 # else 4842393Syz155240 error = SLEEP(&fr_authnext, "fr_authnext"); 4852393Syz155240 # endif /* __osf__ */ 4862393Syz155240 # endif /* __hpux */ 4872393Syz155240 # endif /* SOLARIS */ 4882393Syz155240 #endif 4892393Syz155240 MUTEX_EXIT(&ipf_authmx); 4902393Syz155240 READ_ENTER(&ipf_global); 4912393Syz155240 if (error == 0) { 4922393Syz155240 READ_ENTER(&ipf_auth); 4932393Syz155240 goto fr_authioctlloop; 4942393Syz155240 } 4952393Syz155240 break; 4962393Syz155240 4972393Syz155240 case SIOCAUTHR: 4982393Syz155240 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 4992393Syz155240 if (error != 0) 5002393Syz155240 return error; 5012393Syz155240 SPL_NET(s); 5022393Syz155240 WRITE_ENTER(&ipf_auth); 5032393Syz155240 i = au->fra_index; 5042393Syz155240 fra = fr_auth + i; 5052393Syz155240 if ((i < 0) || (i >= fr_authsize) || 5062393Syz155240 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 5072393Syz155240 RWLOCK_EXIT(&ipf_auth); 5082393Syz155240 SPL_X(s); 5092393Syz155240 return ESRCH; 5102393Syz155240 } 5112393Syz155240 m = fr_authpkts[i]; 5122393Syz155240 fra->fra_index = -2; 5132393Syz155240 fra->fra_pass = au->fra_pass; 5142393Syz155240 fr_authpkts[i] = NULL; 5152393Syz155240 RWLOCK_EXIT(&ipf_auth); 516*2958Sdr146992 5172393Syz155240 #ifdef _KERNEL 518*2958Sdr146992 if (fra->fra_info.fin_v == 4) { 519*2958Sdr146992 net_data_p = ipf_ipv4; 520*2958Sdr146992 } else if (fra->fra_info.fin_v == 6) { 521*2958Sdr146992 net_data_p = ipf_ipv6; 522*2958Sdr146992 } else { 523*2958Sdr146992 return (-1); 524*2958Sdr146992 } 525*2958Sdr146992 526*2958Sdr146992 /* 527*2958Sdr146992 * We're putting the packet back on the same interface 528*2958Sdr146992 * queue that it was originally seen on so that it can 529*2958Sdr146992 * progress through the system properly, with the result 530*2958Sdr146992 * of the auth check done. 531*2958Sdr146992 */ 532*2958Sdr146992 inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp; 533*2958Sdr146992 5342393Syz155240 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 5352393Syz155240 # ifdef MENTAT 536*2958Sdr146992 inj_data.ni_packet = m; 537*2958Sdr146992 ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data); 538*2958Sdr146992 539*2958Sdr146992 if (ret < 0) 540*2958Sdr146992 fr_authstats.fas_sendfail++; 541*2958Sdr146992 else 542*2958Sdr146992 fr_authstats.fas_sendok++; 5432393Syz155240 # else /* MENTAT */ 5442393Syz155240 # if defined(linux) || defined(AIX) 5452393Syz155240 # else 5462393Syz155240 # if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ 5472393Syz155240 (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \ 5482393Syz155240 (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) 5492393Syz155240 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, 5502393Syz155240 NULL); 5512393Syz155240 # else 5522393Syz155240 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 5532393Syz155240 # endif 5542393Syz155240 if (error != 0) 5552393Syz155240 fr_authstats.fas_sendfail++; 5562393Syz155240 else 5572393Syz155240 fr_authstats.fas_sendok++; 558*2958Sdr146992 # endif /* Linux */ 559*2958Sdr146992 # endif /* MENTAT */ 5602393Syz155240 } else if (m) { 5612393Syz155240 # ifdef MENTAT 562*2958Sdr146992 inj_data.ni_packet = m; 563*2958Sdr146992 ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data); 5642393Syz155240 # else /* MENTAT */ 5652393Syz155240 # if defined(linux) || defined(AIX) 5662393Syz155240 # else 5672393Syz155240 # if (__FreeBSD_version >= 501000) 5682393Syz155240 netisr_dispatch(NETISR_IP, m); 5692393Syz155240 # else 5702393Syz155240 # if (IRIX >= 60516) 5712393Syz155240 ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; 5722393Syz155240 # else 5732393Syz155240 ifq = &ipintrq; 5742393Syz155240 # endif 5752393Syz155240 if (IF_QFULL(ifq)) { 5762393Syz155240 IF_DROP(ifq); 5772393Syz155240 FREE_MB_T(m); 5782393Syz155240 error = ENOBUFS; 5792393Syz155240 } else { 5802393Syz155240 IF_ENQUEUE(ifq, m); 5812393Syz155240 # if IRIX < 60500 5822393Syz155240 schednetisr(NETISR_IP); 5832393Syz155240 # endif 5842393Syz155240 } 5852393Syz155240 # endif 5862393Syz155240 # endif /* Linux */ 5872393Syz155240 # endif /* MENTAT */ 5882393Syz155240 if (error != 0) 5892393Syz155240 fr_authstats.fas_quefail++; 5902393Syz155240 else 5912393Syz155240 fr_authstats.fas_queok++; 5922393Syz155240 } else 5932393Syz155240 error = EINVAL; 5942393Syz155240 # ifdef MENTAT 5952393Syz155240 if (error != 0) 5962393Syz155240 error = EINVAL; 5972393Syz155240 # else /* MENTAT */ 5982393Syz155240 /* 5992393Syz155240 * If we experience an error which will result in the packet 6002393Syz155240 * not being processed, make sure we advance to the next one. 6012393Syz155240 */ 6022393Syz155240 if (error == ENOBUFS) { 6032393Syz155240 fr_authused--; 6042393Syz155240 fra->fra_index = -1; 6052393Syz155240 fra->fra_pass = 0; 6062393Syz155240 if (i == fr_authstart) { 6072393Syz155240 while (fra->fra_index == -1) { 6082393Syz155240 i++; 6092393Syz155240 if (i == fr_authsize) 6102393Syz155240 i = 0; 6112393Syz155240 fr_authstart = i; 6122393Syz155240 if (i == fr_authend) 6132393Syz155240 break; 6142393Syz155240 } 6152393Syz155240 if (fr_authstart == fr_authend) { 6162393Syz155240 fr_authnext = 0; 6172393Syz155240 fr_authstart = fr_authend = 0; 6182393Syz155240 } 6192393Syz155240 } 6202393Syz155240 } 6212393Syz155240 # endif /* MENTAT */ 6222393Syz155240 #endif /* _KERNEL */ 6232393Syz155240 SPL_X(s); 6242393Syz155240 break; 6252393Syz155240 6262393Syz155240 default : 6272393Syz155240 error = EINVAL; 6282393Syz155240 break; 6292393Syz155240 } 6302393Syz155240 return error; 6312393Syz155240 } 6322393Syz155240 6332393Syz155240 6342393Syz155240 /* 6352393Syz155240 * Free all network buffer memory used to keep saved packets. 6362393Syz155240 */ 6372393Syz155240 void fr_authunload() 6382393Syz155240 { 6392393Syz155240 register int i; 6402393Syz155240 register frauthent_t *fae, **faep; 6412393Syz155240 frentry_t *fr, **frp; 6422393Syz155240 mb_t *m; 6432393Syz155240 6442393Syz155240 if (fr_auth != NULL) { 6452393Syz155240 KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); 6462393Syz155240 fr_auth = NULL; 6472393Syz155240 } 6482393Syz155240 6492393Syz155240 if (fr_authpkts != NULL) { 6502393Syz155240 for (i = 0; i < fr_authsize; i++) { 6512393Syz155240 m = fr_authpkts[i]; 6522393Syz155240 if (m != NULL) { 6532393Syz155240 FREE_MB_T(m); 6542393Syz155240 fr_authpkts[i] = NULL; 6552393Syz155240 } 6562393Syz155240 } 6572393Syz155240 KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 6582393Syz155240 fr_authpkts = NULL; 6592393Syz155240 } 6602393Syz155240 6612393Syz155240 faep = &fae_list; 6622393Syz155240 while ((fae = *faep) != NULL) { 6632393Syz155240 *faep = fae->fae_next; 6642393Syz155240 KFREE(fae); 6652393Syz155240 } 6662393Syz155240 ipauth = NULL; 6672393Syz155240 6682393Syz155240 if (fr_authlist != NULL) { 6692393Syz155240 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 6702393Syz155240 if (fr->fr_ref == 1) { 6712393Syz155240 *frp = fr->fr_next; 6722393Syz155240 KFREE(fr); 6732393Syz155240 } else 6742393Syz155240 frp = &fr->fr_next; 6752393Syz155240 } 6762393Syz155240 } 6772393Syz155240 6782393Syz155240 if (fr_auth_init == 1) { 6792393Syz155240 # if SOLARIS && defined(_KERNEL) 6802393Syz155240 cv_destroy(&ipfauthwait); 6812393Syz155240 # endif 6822393Syz155240 MUTEX_DESTROY(&ipf_authmx); 6832393Syz155240 RW_DESTROY(&ipf_auth); 6842393Syz155240 6852393Syz155240 fr_auth_init = 0; 6862393Syz155240 } 6872393Syz155240 } 6882393Syz155240 6892393Syz155240 6902393Syz155240 /* 6912393Syz155240 * Slowly expire held auth records. Timeouts are set 6922393Syz155240 * in expectation of this being called twice per second. 6932393Syz155240 */ 6942393Syz155240 void fr_authexpire() 6952393Syz155240 { 6962393Syz155240 register int i; 6972393Syz155240 register frauth_t *fra; 6982393Syz155240 register frauthent_t *fae, **faep; 6992393Syz155240 register frentry_t *fr, **frp; 7002393Syz155240 mb_t *m; 7012393Syz155240 SPL_INT(s); 7022393Syz155240 7032393Syz155240 if (fr_auth_lock) 7042393Syz155240 return; 7052393Syz155240 7062393Syz155240 SPL_NET(s); 7072393Syz155240 WRITE_ENTER(&ipf_auth); 7082393Syz155240 for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { 7092393Syz155240 fra->fra_age--; 7102393Syz155240 if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { 7112393Syz155240 FREE_MB_T(m); 7122393Syz155240 fr_authpkts[i] = NULL; 7132393Syz155240 fr_auth[i].fra_index = -1; 7142393Syz155240 fr_authstats.fas_expire++; 7152393Syz155240 fr_authused--; 7162393Syz155240 } 7172393Syz155240 } 7182393Syz155240 7192393Syz155240 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 7202393Syz155240 fae->fae_age--; 7212393Syz155240 if (fae->fae_age == 0) { 7222393Syz155240 *faep = fae->fae_next; 7232393Syz155240 KFREE(fae); 7242393Syz155240 fr_authstats.fas_expire++; 7252393Syz155240 } else 7262393Syz155240 faep = &fae->fae_next; 7272393Syz155240 } 7282393Syz155240 if (fae_list != NULL) 7292393Syz155240 ipauth = &fae_list->fae_fr; 7302393Syz155240 else 7312393Syz155240 ipauth = NULL; 7322393Syz155240 7332393Syz155240 for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 7342393Syz155240 if (fr->fr_ref == 1) { 7352393Syz155240 *frp = fr->fr_next; 7362393Syz155240 KFREE(fr); 7372393Syz155240 } else 7382393Syz155240 frp = &fr->fr_next; 7392393Syz155240 } 7402393Syz155240 RWLOCK_EXIT(&ipf_auth); 7412393Syz155240 SPL_X(s); 7422393Syz155240 } 7432393Syz155240 7442393Syz155240 int fr_preauthcmd(cmd, fr, frptr) 7452393Syz155240 ioctlcmd_t cmd; 7462393Syz155240 frentry_t *fr, **frptr; 7472393Syz155240 { 7482393Syz155240 frauthent_t *fae, **faep; 7492393Syz155240 int error = 0; 7502393Syz155240 SPL_INT(s); 7512393Syz155240 7522393Syz155240 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 7532393Syz155240 return EIO; 7542393Syz155240 7552393Syz155240 for (faep = &fae_list; ((fae = *faep) != NULL); ) { 7562393Syz155240 if (&fae->fae_fr == fr) 7572393Syz155240 break; 7582393Syz155240 else 7592393Syz155240 faep = &fae->fae_next; 7602393Syz155240 } 7612393Syz155240 7622393Syz155240 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 7632393Syz155240 if (fr == NULL || frptr == NULL) 7642393Syz155240 error = EINVAL; 7652393Syz155240 else if (fae == NULL) 7662393Syz155240 error = ESRCH; 7672393Syz155240 else { 7682393Syz155240 SPL_NET(s); 7692393Syz155240 WRITE_ENTER(&ipf_auth); 7702393Syz155240 *faep = fae->fae_next; 7712393Syz155240 if (ipauth == &fae->fae_fr) 7722393Syz155240 ipauth = fae_list ? &fae_list->fae_fr : NULL; 7732393Syz155240 RWLOCK_EXIT(&ipf_auth); 7742393Syz155240 SPL_X(s); 7752393Syz155240 7762393Syz155240 KFREE(fae); 7772393Syz155240 } 7782393Syz155240 } else if (fr != NULL && frptr != NULL) { 7792393Syz155240 KMALLOC(fae, frauthent_t *); 7802393Syz155240 if (fae != NULL) { 7812393Syz155240 bcopy((char *)fr, (char *)&fae->fae_fr, 7822393Syz155240 sizeof(*fr)); 7832393Syz155240 SPL_NET(s); 7842393Syz155240 WRITE_ENTER(&ipf_auth); 7852393Syz155240 fae->fae_age = fr_defaultauthage; 7862393Syz155240 fae->fae_fr.fr_hits = 0; 7872393Syz155240 fae->fae_fr.fr_next = *frptr; 7882393Syz155240 *frptr = &fae->fae_fr; 7892393Syz155240 fae->fae_next = *faep; 7902393Syz155240 *faep = fae; 7912393Syz155240 ipauth = &fae_list->fae_fr; 7922393Syz155240 RWLOCK_EXIT(&ipf_auth); 7932393Syz155240 SPL_X(s); 7942393Syz155240 } else 7952393Syz155240 error = ENOMEM; 7962393Syz155240 } else 7972393Syz155240 error = EINVAL; 7982393Syz155240 return error; 7992393Syz155240 } 8002393Syz155240 8012393Syz155240 8022393Syz155240 /* 8032393Syz155240 * Flush held packets. 8042393Syz155240 * Must already be properly SPL'ed and Locked on &ipf_auth. 8052393Syz155240 * 8062393Syz155240 */ 8072393Syz155240 int fr_authflush() 8082393Syz155240 { 8092393Syz155240 register int i, num_flushed; 8102393Syz155240 mb_t *m; 8112393Syz155240 8122393Syz155240 if (fr_auth_lock) 8132393Syz155240 return -1; 8142393Syz155240 8152393Syz155240 num_flushed = 0; 8162393Syz155240 8172393Syz155240 for (i = 0 ; i < fr_authsize; i++) { 8182393Syz155240 m = fr_authpkts[i]; 8192393Syz155240 if (m != NULL) { 8202393Syz155240 FREE_MB_T(m); 8212393Syz155240 fr_authpkts[i] = NULL; 8222393Syz155240 fr_auth[i].fra_index = -1; 8232393Syz155240 /* perhaps add & use a flush counter inst.*/ 8242393Syz155240 fr_authstats.fas_expire++; 8252393Syz155240 fr_authused--; 8262393Syz155240 num_flushed++; 8272393Syz155240 } 8282393Syz155240 } 8292393Syz155240 8302393Syz155240 fr_authstart = 0; 8312393Syz155240 fr_authend = 0; 8322393Syz155240 fr_authnext = 0; 8332393Syz155240 8342393Syz155240 return num_flushed; 8352393Syz155240 } 836