12393Syz155240 /* 22393Syz155240 * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 32393Syz155240 * 42393Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 53448Sdh155122 * 66518Sjojemann * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 72958Sdr146992 * Use is subject to license terms. 82958Sdr146992 */ 92958Sdr146992 102393Syz155240 #if defined(KERNEL) || defined(_KERNEL) 112393Syz155240 # undef KERNEL 122393Syz155240 # undef _KERNEL 132393Syz155240 # define KERNEL 1 142393Syz155240 # define _KERNEL 1 152393Syz155240 #endif 162393Syz155240 #include <sys/errno.h> 172393Syz155240 #include <sys/types.h> 182393Syz155240 #include <sys/param.h> 192393Syz155240 #include <sys/time.h> 202393Syz155240 #include <sys/file.h> 212393Syz155240 #if !defined(_KERNEL) 222393Syz155240 # include <stdio.h> 232393Syz155240 # include <stdlib.h> 242393Syz155240 # include <string.h> 252393Syz155240 # define _KERNEL 262393Syz155240 # ifdef __OpenBSD__ 272393Syz155240 struct file; 282393Syz155240 # endif 292393Syz155240 # include <sys/uio.h> 302393Syz155240 # undef _KERNEL 312393Syz155240 #endif 322393Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 332393Syz155240 # include <sys/filio.h> 342393Syz155240 # include <sys/fcntl.h> 352393Syz155240 #else 362393Syz155240 # include <sys/ioctl.h> 372393Syz155240 #endif 382393Syz155240 #if !defined(linux) 392393Syz155240 # include <sys/protosw.h> 402393Syz155240 #endif 412393Syz155240 #include <sys/socket.h> 422393Syz155240 #if defined(_KERNEL) 432393Syz155240 # include <sys/systm.h> 442393Syz155240 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 452393Syz155240 # include <sys/mbuf.h> 462393Syz155240 # endif 472393Syz155240 #endif 482393Syz155240 #if defined(__SVR4) || defined(__svr4__) 492393Syz155240 # include <sys/filio.h> 502393Syz155240 # include <sys/byteorder.h> 512393Syz155240 # ifdef _KERNEL 522393Syz155240 # include <sys/dditypes.h> 532393Syz155240 # endif 542393Syz155240 # include <sys/stream.h> 552393Syz155240 # include <sys/kmem.h> 562958Sdr146992 # include <sys/neti.h> 572393Syz155240 #endif 582393Syz155240 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) 592393Syz155240 # include <sys/queue.h> 602393Syz155240 #endif 612393Syz155240 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 622393Syz155240 # include <machine/cpu.h> 632393Syz155240 #endif 642393Syz155240 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 652393Syz155240 # include <sys/proc.h> 662393Syz155240 #endif 672393Syz155240 #include <net/if.h> 682393Syz155240 #ifdef sun 692393Syz155240 # include <net/af.h> 702393Syz155240 #endif 712393Syz155240 #include <net/route.h> 722393Syz155240 #include <netinet/in.h> 732393Syz155240 #include <netinet/in_systm.h> 742393Syz155240 #include <netinet/ip.h> 752393Syz155240 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 762393Syz155240 # define KERNEL 772393Syz155240 # define _KERNEL 782393Syz155240 # define NOT_KERNEL 792393Syz155240 #endif 802393Syz155240 #if !defined(linux) 812393Syz155240 # include <netinet/ip_var.h> 822393Syz155240 #endif 832393Syz155240 #ifdef NOT_KERNEL 842393Syz155240 # undef _KERNEL 852393Syz155240 # undef KERNEL 862393Syz155240 #endif 872393Syz155240 #include <netinet/tcp.h> 882393Syz155240 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 892393Syz155240 extern struct ifqueue ipintrq; /* ip packet input queue */ 902393Syz155240 #else 912393Syz155240 # if !defined(__hpux) && !defined(linux) 922393Syz155240 # if __FreeBSD_version >= 300000 932393Syz155240 # include <net/if_var.h> 942393Syz155240 # if __FreeBSD_version >= 500042 952393Syz155240 # define IF_QFULL _IF_QFULL 962393Syz155240 # define IF_DROP _IF_DROP 972393Syz155240 # endif /* __FreeBSD_version >= 500042 */ 982393Syz155240 # endif 992393Syz155240 # include <netinet/in_var.h> 1002393Syz155240 # include <netinet/tcp_fsm.h> 1012393Syz155240 # endif 1022393Syz155240 #endif 1032393Syz155240 #include <netinet/udp.h> 1042393Syz155240 #include <netinet/ip_icmp.h> 1052393Syz155240 #include "netinet/ip_compat.h" 1062393Syz155240 #include <netinet/tcpip.h> 1073448Sdh155122 #include "netinet/ipf_stack.h" 1082393Syz155240 #include "netinet/ip_fil.h" 1092393Syz155240 #include "netinet/ip_auth.h" 1102393Syz155240 #if !defined(MENTAT) && !defined(linux) 1112393Syz155240 # include <net/netisr.h> 1122393Syz155240 # ifdef __FreeBSD__ 1132393Syz155240 # include <machine/cpufunc.h> 1142393Syz155240 # endif 1152393Syz155240 #endif 1162393Syz155240 #if (__FreeBSD_version >= 300000) 1172393Syz155240 # include <sys/malloc.h> 1182393Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 1192393Syz155240 # include <sys/libkern.h> 1202393Syz155240 # include <sys/systm.h> 1212393Syz155240 # endif 1222393Syz155240 #endif 1232393Syz155240 /* END OF INCLUDES */ 1242393Syz155240 1252393Syz155240 #if !defined(lint) 1262393Syz155240 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $"; 1272393Syz155240 #endif 1282393Syz155240 1293448Sdh155122 void fr_authderef __P((frauthent_t **)); 1303448Sdh155122 int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 1312393Syz155240 1322393Syz155240 1333448Sdh155122 int fr_authinit(ifs) 1343448Sdh155122 ipf_stack_t *ifs; 1353448Sdh155122 { 1363448Sdh155122 KMALLOCS(ifs->ifs_fr_auth, frauth_t *, 1373448Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 1383448Sdh155122 if (ifs->ifs_fr_auth != NULL) 1393448Sdh155122 bzero((char *)ifs->ifs_fr_auth, 1403448Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 1412393Syz155240 else 1422393Syz155240 return -1; 1432393Syz155240 1443448Sdh155122 KMALLOCS(ifs->ifs_fr_authpkts, mb_t **, 1453448Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 1463448Sdh155122 if (ifs->ifs_fr_authpkts != NULL) 1473448Sdh155122 bzero((char *)ifs->ifs_fr_authpkts, 1483448Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 1492393Syz155240 else 1502393Syz155240 return -2; 1512393Syz155240 1523448Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_authmx, "ipf auth log mutex"); 1533448Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_auth, "ipf IP User-Auth rwlock"); 1542393Syz155240 #if SOLARIS && defined(_KERNEL) 1553448Sdh155122 cv_init(&ifs->ifs_ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 1562393Syz155240 #endif 1572393Syz155240 #if defined(linux) && defined(_KERNEL) 1582393Syz155240 init_waitqueue_head(&fr_authnext_linux); 1592393Syz155240 #endif 1602393Syz155240 1613448Sdh155122 ifs->ifs_fr_auth_init = 1; 1622393Syz155240 1632393Syz155240 return 0; 1642393Syz155240 } 1652393Syz155240 1662393Syz155240 1672393Syz155240 /* 1682393Syz155240 * Check if a packet has authorization. If the packet is found to match an 1692393Syz155240 * authorization result and that would result in a feedback loop (i.e. it 1702393Syz155240 * will end up returning FR_AUTH) then return FR_BLOCK instead. 1712393Syz155240 */ 1722393Syz155240 frentry_t *fr_checkauth(fin, passp) 1732393Syz155240 fr_info_t *fin; 1742393Syz155240 u_32_t *passp; 1752393Syz155240 { 1762393Syz155240 frentry_t *fr; 1772393Syz155240 frauth_t *fra; 1782393Syz155240 u_32_t pass; 1792393Syz155240 u_short id; 1802393Syz155240 ip_t *ip; 1812393Syz155240 int i; 1823448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 1832393Syz155240 1843448Sdh155122 if (ifs->ifs_fr_auth_lock || !ifs->ifs_fr_authused) 1852393Syz155240 return NULL; 1862393Syz155240 1872393Syz155240 ip = fin->fin_ip; 1882393Syz155240 id = ip->ip_id; 1892393Syz155240 1903448Sdh155122 READ_ENTER(&ifs->ifs_ipf_auth); 1913448Sdh155122 for (i = ifs->ifs_fr_authstart; i != ifs->ifs_fr_authend; ) { 1922393Syz155240 /* 1932393Syz155240 * index becomes -2 only after an SIOCAUTHW. Check this in 1942393Syz155240 * case the same packet gets sent again and it hasn't yet been 1952393Syz155240 * auth'd. 1962393Syz155240 */ 1973448Sdh155122 fra = ifs->ifs_fr_auth + i; 1982393Syz155240 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 1992393Syz155240 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 2002393Syz155240 /* 2012393Syz155240 * Avoid feedback loop. 2022393Syz155240 */ 2032393Syz155240 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 2042393Syz155240 pass = FR_BLOCK; 2052393Syz155240 /* 2062393Syz155240 * Create a dummy rule for the stateful checking to 2072393Syz155240 * use and return. Zero out any values we don't 2082393Syz155240 * trust from userland! 2092393Syz155240 */ 2102393Syz155240 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 2112393Syz155240 (fin->fin_flx & FI_FRAG))) { 2122393Syz155240 KMALLOC(fr, frentry_t *); 2132393Syz155240 if (fr) { 2142393Syz155240 bcopy((char *)fra->fra_info.fin_fr, 2152393Syz155240 (char *)fr, sizeof(*fr)); 2162393Syz155240 fr->fr_grp = NULL; 2172393Syz155240 fr->fr_ifa = fin->fin_ifp; 2182393Syz155240 fr->fr_func = NULL; 2192393Syz155240 fr->fr_ref = 1; 2202393Syz155240 fr->fr_flags = pass; 2212393Syz155240 fr->fr_ifas[1] = NULL; 2222393Syz155240 fr->fr_ifas[2] = NULL; 2232393Syz155240 fr->fr_ifas[3] = NULL; 2242393Syz155240 } 2252393Syz155240 } else 2262393Syz155240 fr = fra->fra_info.fin_fr; 2272393Syz155240 fin->fin_fr = fr; 2283448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 2293448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 2302393Syz155240 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 2313448Sdh155122 fr->fr_next = ifs->ifs_fr_authlist; 2323448Sdh155122 ifs->ifs_fr_authlist = fr; 2332393Syz155240 } 2343448Sdh155122 ifs->ifs_fr_authstats.fas_hits++; 2352393Syz155240 fra->fra_index = -1; 2363448Sdh155122 ifs->ifs_fr_authused--; 2373448Sdh155122 if (i == ifs->ifs_fr_authstart) { 2382393Syz155240 while (fra->fra_index == -1) { 2392393Syz155240 i++; 2402393Syz155240 fra++; 2413448Sdh155122 if (i == ifs->ifs_fr_authsize) { 2422393Syz155240 i = 0; 2433448Sdh155122 fra = ifs->ifs_fr_auth; 2442393Syz155240 } 2453448Sdh155122 ifs->ifs_fr_authstart = i; 2463448Sdh155122 if (i == ifs->ifs_fr_authend) 2472393Syz155240 break; 2482393Syz155240 } 2493448Sdh155122 if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 2503448Sdh155122 ifs->ifs_fr_authnext = 0; 2513448Sdh155122 ifs->ifs_fr_authstart = 0; 2523448Sdh155122 ifs->ifs_fr_authend = 0; 2532393Syz155240 } 2542393Syz155240 } 2553448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 2562393Syz155240 if (passp != NULL) 2572393Syz155240 *passp = pass; 2583448Sdh155122 ATOMIC_INC64(ifs->ifs_fr_authstats.fas_hits); 2592393Syz155240 return fr; 2602393Syz155240 } 2612393Syz155240 i++; 2623448Sdh155122 if (i == ifs->ifs_fr_authsize) 2632393Syz155240 i = 0; 2642393Syz155240 } 2653448Sdh155122 ifs->ifs_fr_authstats.fas_miss++; 2663448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 2673448Sdh155122 ATOMIC_INC64(ifs->ifs_fr_authstats.fas_miss); 2682393Syz155240 return NULL; 2692393Syz155240 } 2702393Syz155240 2712393Syz155240 2722393Syz155240 /* 2732393Syz155240 * Check if we have room in the auth array to hold details for another packet. 2742393Syz155240 * If we do, store it and wake up any user programs which are waiting to 2752393Syz155240 * hear about these events. 2762393Syz155240 */ 2772393Syz155240 int fr_newauth(m, fin) 2782393Syz155240 mb_t *m; 2792393Syz155240 fr_info_t *fin; 2802393Syz155240 { 2812393Syz155240 #if defined(_KERNEL) && defined(MENTAT) 2822393Syz155240 qpktinfo_t *qpi = fin->fin_qpi; 2832393Syz155240 #endif 2842393Syz155240 frauth_t *fra; 2852393Syz155240 #if !defined(sparc) && !defined(m68k) 2862393Syz155240 ip_t *ip; 2872393Syz155240 #endif 2882393Syz155240 int i; 2893448Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 2902393Syz155240 2913448Sdh155122 if (ifs->ifs_fr_auth_lock) 2922393Syz155240 return 0; 2932393Syz155240 2943448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 2953448Sdh155122 if (ifs->ifs_fr_authstart > ifs->ifs_fr_authend) { 2963448Sdh155122 ifs->ifs_fr_authstats.fas_nospace++; 2973448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 2982393Syz155240 return 0; 2992393Syz155240 } else { 3003448Sdh155122 if (ifs->ifs_fr_authused == ifs->ifs_fr_authsize) { 3013448Sdh155122 ifs->ifs_fr_authstats.fas_nospace++; 3023448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 3032393Syz155240 return 0; 3042393Syz155240 } 3052393Syz155240 } 3062393Syz155240 3073448Sdh155122 ifs->ifs_fr_authstats.fas_added++; 3083448Sdh155122 ifs->ifs_fr_authused++; 3093448Sdh155122 i = ifs->ifs_fr_authend++; 3103448Sdh155122 if (ifs->ifs_fr_authend == ifs->ifs_fr_authsize) 3113448Sdh155122 ifs->ifs_fr_authend = 0; 3123448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 3132393Syz155240 3143448Sdh155122 fra = ifs->ifs_fr_auth + i; 3152393Syz155240 fra->fra_index = i; 3162393Syz155240 fra->fra_pass = 0; 3173448Sdh155122 fra->fra_age = ifs->ifs_fr_defaultauthage; 3182393Syz155240 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 3192393Syz155240 #if !defined(sparc) && !defined(m68k) 3202393Syz155240 /* 3212393Syz155240 * No need to copyback here as we want to undo the changes, not keep 3222393Syz155240 * them. 3232393Syz155240 */ 3242393Syz155240 ip = fin->fin_ip; 3252393Syz155240 # if defined(MENTAT) && defined(_KERNEL) 3262393Syz155240 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 3272393Syz155240 # endif 3282393Syz155240 { 3292393Syz155240 register u_short bo; 3302393Syz155240 3312393Syz155240 bo = ip->ip_len; 3322393Syz155240 ip->ip_len = htons(bo); 3332393Syz155240 bo = ip->ip_off; 3342393Syz155240 ip->ip_off = htons(bo); 3352393Syz155240 } 3362393Syz155240 #endif 3372393Syz155240 #if SOLARIS && defined(_KERNEL) 3382393Syz155240 m->b_rptr -= qpi->qpi_off; 3393448Sdh155122 ifs->ifs_fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 3403448Sdh155122 cv_signal(&ifs->ifs_ipfauthwait); 3412393Syz155240 #else 3422393Syz155240 # if defined(BSD) && !defined(sparc) && (BSD >= 199306) 3432393Syz155240 if (!fin->fin_out) { 3442393Syz155240 ip->ip_len = htons(ip->ip_len); 3452393Syz155240 ip->ip_off = htons(ip->ip_off); 3462393Syz155240 } 3472393Syz155240 # endif 3483448Sdh155122 ifs->ifs_fr_authpkts[i] = m; 3493448Sdh155122 WAKEUP(&ifs->ifs_fr_authnext, 0); 3502393Syz155240 #endif 3512393Syz155240 return 1; 3522393Syz155240 } 3532393Syz155240 3542393Syz155240 3553448Sdh155122 int fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs) 3562393Syz155240 caddr_t data; 3572393Syz155240 ioctlcmd_t cmd; 3583448Sdh155122 int mode,uid; 3593448Sdh155122 void *ctx; 3603448Sdh155122 ipf_stack_t *ifs; 3612393Syz155240 { 3622393Syz155240 mb_t *m; 3632393Syz155240 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 3642393Syz155240 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 3652393Syz155240 struct ifqueue *ifq; 3662393Syz155240 SPL_INT(s); 3672393Syz155240 #endif 3682393Syz155240 frauth_t auth, *au = &auth, *fra; 3692393Syz155240 int i, error = 0, len; 3702393Syz155240 char *t; 3712958Sdr146992 net_data_t net_data_p; 3722958Sdr146992 net_inject_t inj_data; 3732958Sdr146992 int ret; 3742393Syz155240 3752393Syz155240 switch (cmd) 3762393Syz155240 { 3773448Sdh155122 case SIOCGENITER : 3783448Sdh155122 { 3793448Sdh155122 ipftoken_t *token; 3803448Sdh155122 ipfgeniter_t iter; 3813448Sdh155122 3823448Sdh155122 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 3833448Sdh155122 if (error != 0) 3843448Sdh155122 break; 3853448Sdh155122 3863448Sdh155122 token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx, ifs); 3873448Sdh155122 if (token != NULL) 3883448Sdh155122 error = fr_authgeniter(token, &iter, ifs); 3893448Sdh155122 else 3903448Sdh155122 error = ESRCH; 3913448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 3923448Sdh155122 3933448Sdh155122 break; 3943448Sdh155122 } 3953448Sdh155122 3962393Syz155240 case SIOCSTLCK : 3972393Syz155240 if (!(mode & FWRITE)) { 3982393Syz155240 error = EPERM; 3992393Syz155240 break; 4002393Syz155240 } 401*7433SJohn.Ojemann@Sun.COM error = fr_lock(data, &ifs->ifs_fr_auth_lock); 4022393Syz155240 break; 4032393Syz155240 4042393Syz155240 case SIOCATHST: 4053448Sdh155122 ifs->ifs_fr_authstats.fas_faelist = ifs->ifs_fae_list; 4063448Sdh155122 error = fr_outobj(data, &ifs->ifs_fr_authstats, 4073448Sdh155122 IPFOBJ_AUTHSTAT); 4082393Syz155240 break; 4092393Syz155240 4102393Syz155240 case SIOCIPFFL: 4112393Syz155240 SPL_NET(s); 4123448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 4133448Sdh155122 i = fr_authflush(ifs); 4143448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4152393Syz155240 SPL_X(s); 4162393Syz155240 error = copyoutptr((char *)&i, data, sizeof(i)); 4172393Syz155240 break; 4182393Syz155240 4192393Syz155240 case SIOCAUTHW: 4202393Syz155240 fr_authioctlloop: 4212393Syz155240 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 4223448Sdh155122 READ_ENTER(&ifs->ifs_ipf_auth); 4233448Sdh155122 if ((ifs->ifs_fr_authnext != ifs->ifs_fr_authend) && 4243448Sdh155122 ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]) { 4253448Sdh155122 error = fr_outobj(data, 4263448Sdh155122 &ifs->ifs_fr_auth[ifs->ifs_fr_authnext], 4272393Syz155240 IPFOBJ_FRAUTH); 4282393Syz155240 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 4292393Syz155240 /* 4302393Syz155240 * Copy packet contents out to user space if 4312393Syz155240 * requested. Bail on an error. 4322393Syz155240 */ 4333448Sdh155122 m = ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]; 4342393Syz155240 len = MSGDSIZE(m); 4352393Syz155240 if (len > auth.fra_len) 4362393Syz155240 len = auth.fra_len; 4372393Syz155240 auth.fra_len = len; 4382393Syz155240 for (t = auth.fra_buf; m && (len > 0); ) { 4392393Syz155240 i = MIN(M_LEN(m), len); 4402393Syz155240 error = copyoutptr(MTOD(m, char *), 4412393Syz155240 t, i); 4422393Syz155240 len -= i; 4432393Syz155240 t += i; 4442393Syz155240 if (error != 0) 4452393Syz155240 break; 4462393Syz155240 } 4472393Syz155240 } 4483448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4492393Syz155240 if (error != 0) 4502393Syz155240 break; 4512393Syz155240 SPL_NET(s); 4523448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 4533448Sdh155122 ifs->ifs_fr_authnext++; 4543448Sdh155122 if (ifs->ifs_fr_authnext == ifs->ifs_fr_authsize) 4553448Sdh155122 ifs->ifs_fr_authnext = 0; 4563448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4572393Syz155240 SPL_X(s); 4582393Syz155240 return 0; 4592393Syz155240 } 4603448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4612393Syz155240 /* 4622393Syz155240 * We exit ipf_global here because a program that enters in 4632393Syz155240 * here will have a lock on it and goto sleep having this lock. 4642393Syz155240 * If someone were to do an 'ipf -D' the system would then 4652393Syz155240 * deadlock. The catch with releasing it here is that the 4662393Syz155240 * caller of this function expects it to be held when we 4672393Syz155240 * return so we have to reacquire it in here. 4682393Syz155240 */ 4693448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 4702393Syz155240 4713448Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_authmx); 4722393Syz155240 #ifdef _KERNEL 4732393Syz155240 # if SOLARIS 4742393Syz155240 error = 0; 4753448Sdh155122 if (!cv_wait_sig(&ifs->ifs_ipfauthwait, &ifs->ifs_ipf_authmx.ipf_lk)) 4762393Syz155240 error = EINTR; 4772393Syz155240 # else /* SOLARIS */ 4782393Syz155240 # ifdef __hpux 4792393Syz155240 { 4802393Syz155240 lock_t *l; 4812393Syz155240 4823448Sdh155122 l = get_sleep_lock(&ifs->ifs_fr_authnext); 4833448Sdh155122 error = sleep(&ifs->ifs_fr_authnext, PZERO+1); 4842393Syz155240 spinunlock(l); 4852393Syz155240 } 4862393Syz155240 # else 4872393Syz155240 # ifdef __osf__ 4883448Sdh155122 error = mpsleep(&ifs->ifs_fr_authnext, PSUSP|PCATCH, 4893448Sdh155122 "fr_authnext", 0, 4903448Sdh155122 &ifs->ifs_ipf_authmx, MS_LOCK_SIMPLE); 4912393Syz155240 # else 4923448Sdh155122 error = SLEEP(&ifs->ifs_fr_authnext, "fr_authnext"); 4932393Syz155240 # endif /* __osf__ */ 4942393Syz155240 # endif /* __hpux */ 4952393Syz155240 # endif /* SOLARIS */ 4962393Syz155240 #endif 4973448Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_authmx); 4983448Sdh155122 READ_ENTER(&ifs->ifs_ipf_global); 4992393Syz155240 if (error == 0) { 5003448Sdh155122 READ_ENTER(&ifs->ifs_ipf_auth); 5012393Syz155240 goto fr_authioctlloop; 5022393Syz155240 } 5032393Syz155240 break; 5042393Syz155240 5052393Syz155240 case SIOCAUTHR: 5062393Syz155240 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 5072393Syz155240 if (error != 0) 5082393Syz155240 return error; 5092393Syz155240 SPL_NET(s); 5103448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 5112393Syz155240 i = au->fra_index; 5123448Sdh155122 fra = ifs->ifs_fr_auth + i; 5133448Sdh155122 if ((i < 0) || (i >= ifs->ifs_fr_authsize) || 5142393Syz155240 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 5153448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 5162393Syz155240 SPL_X(s); 5172393Syz155240 return ESRCH; 5182393Syz155240 } 5193448Sdh155122 m = ifs->ifs_fr_authpkts[i]; 5202393Syz155240 fra->fra_index = -2; 5212393Syz155240 fra->fra_pass = au->fra_pass; 5223448Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 5233448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 5242393Syz155240 #ifdef _KERNEL 5252958Sdr146992 if (fra->fra_info.fin_v == 4) { 5263448Sdh155122 net_data_p = ifs->ifs_ipf_ipv4; 5272958Sdr146992 } else if (fra->fra_info.fin_v == 6) { 5283448Sdh155122 net_data_p = ifs->ifs_ipf_ipv6; 5292958Sdr146992 } else { 5302958Sdr146992 return (-1); 5312958Sdr146992 } 5322958Sdr146992 5332958Sdr146992 /* 5342958Sdr146992 * We're putting the packet back on the same interface 5352958Sdr146992 * queue that it was originally seen on so that it can 5362958Sdr146992 * progress through the system properly, with the result 5372958Sdr146992 * of the auth check done. 5382958Sdr146992 */ 5392958Sdr146992 inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp; 5402958Sdr146992 5412393Syz155240 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 5422393Syz155240 # ifdef MENTAT 5432958Sdr146992 inj_data.ni_packet = m; 5442958Sdr146992 ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data); 5452958Sdr146992 5462958Sdr146992 if (ret < 0) 5473448Sdh155122 ifs->ifs_fr_authstats.fas_sendfail++; 5482958Sdr146992 else 5493448Sdh155122 ifs->ifs_fr_authstats.fas_sendok++; 5502393Syz155240 # else /* MENTAT */ 5512393Syz155240 # if defined(linux) || defined(AIX) 5522393Syz155240 # else 5532393Syz155240 # if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ 5542393Syz155240 (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \ 5552393Syz155240 (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) 5562393Syz155240 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, 5572393Syz155240 NULL); 5582393Syz155240 # else 5592393Syz155240 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 5602393Syz155240 # endif 5612393Syz155240 if (error != 0) 5623448Sdh155122 ifs->ifs_fr_authstats.fas_sendfail++; 5632393Syz155240 else 5643448Sdh155122 ifs->ifs_fr_authstats.fas_sendok++; 5652958Sdr146992 # endif /* Linux */ 5662958Sdr146992 # endif /* MENTAT */ 5672393Syz155240 } else if (m) { 5682393Syz155240 # ifdef MENTAT 5692958Sdr146992 inj_data.ni_packet = m; 5702958Sdr146992 ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data); 5712393Syz155240 # else /* MENTAT */ 5722393Syz155240 # if defined(linux) || defined(AIX) 5732393Syz155240 # else 5742393Syz155240 # if (__FreeBSD_version >= 501000) 5752393Syz155240 netisr_dispatch(NETISR_IP, m); 5762393Syz155240 # else 5772393Syz155240 # if (IRIX >= 60516) 5782393Syz155240 ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; 5792393Syz155240 # else 5802393Syz155240 ifq = &ipintrq; 5812393Syz155240 # endif 5822393Syz155240 if (IF_QFULL(ifq)) { 5832393Syz155240 IF_DROP(ifq); 5842393Syz155240 FREE_MB_T(m); 5852393Syz155240 error = ENOBUFS; 5862393Syz155240 } else { 5872393Syz155240 IF_ENQUEUE(ifq, m); 5882393Syz155240 # if IRIX < 60500 5892393Syz155240 schednetisr(NETISR_IP); 5902393Syz155240 # endif 5912393Syz155240 } 5922393Syz155240 # endif 5932393Syz155240 # endif /* Linux */ 5942393Syz155240 # endif /* MENTAT */ 5952393Syz155240 if (error != 0) 5963448Sdh155122 ifs->ifs_fr_authstats.fas_quefail++; 5972393Syz155240 else 5983448Sdh155122 ifs->ifs_fr_authstats.fas_queok++; 5992393Syz155240 } else 6002393Syz155240 error = EINVAL; 6012393Syz155240 # ifdef MENTAT 6022393Syz155240 if (error != 0) 6032393Syz155240 error = EINVAL; 6042393Syz155240 # else /* MENTAT */ 6052393Syz155240 /* 6062393Syz155240 * If we experience an error which will result in the packet 6072393Syz155240 * not being processed, make sure we advance to the next one. 6082393Syz155240 */ 6092393Syz155240 if (error == ENOBUFS) { 6103448Sdh155122 ifs->ifs_fr_authused--; 6112393Syz155240 fra->fra_index = -1; 6122393Syz155240 fra->fra_pass = 0; 6133448Sdh155122 if (i == ifs->ifs_fr_authstart) { 6142393Syz155240 while (fra->fra_index == -1) { 6152393Syz155240 i++; 6163448Sdh155122 if (i == ifs->ifs_fr_authsize) 6172393Syz155240 i = 0; 6183448Sdh155122 ifs->ifs_fr_authstart = i; 6193448Sdh155122 if (i == ifs->ifs_fr_authend) 6202393Syz155240 break; 6212393Syz155240 } 6223448Sdh155122 if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 6233448Sdh155122 ifs->ifs_fr_authnext = 0; 6243448Sdh155122 ifs->ifs_fr_authstart = 0; 6253448Sdh155122 ifs->ifs_fr_authend = 0; 6262393Syz155240 } 6272393Syz155240 } 6282393Syz155240 } 6292393Syz155240 # endif /* MENTAT */ 6302393Syz155240 #endif /* _KERNEL */ 6312393Syz155240 SPL_X(s); 6322393Syz155240 break; 6332393Syz155240 6342393Syz155240 default : 6352393Syz155240 error = EINVAL; 6362393Syz155240 break; 6372393Syz155240 } 6382393Syz155240 return error; 6392393Syz155240 } 6402393Syz155240 6412393Syz155240 6422393Syz155240 /* 6432393Syz155240 * Free all network buffer memory used to keep saved packets. 6442393Syz155240 */ 6453448Sdh155122 void fr_authunload(ifs) 6463448Sdh155122 ipf_stack_t *ifs; 6472393Syz155240 { 6482393Syz155240 register int i; 6492393Syz155240 register frauthent_t *fae, **faep; 6502393Syz155240 frentry_t *fr, **frp; 6512393Syz155240 mb_t *m; 6522393Syz155240 6533448Sdh155122 if (ifs->ifs_fr_auth != NULL) { 6543448Sdh155122 KFREES(ifs->ifs_fr_auth, 6553448Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 6563448Sdh155122 ifs->ifs_fr_auth = NULL; 6572393Syz155240 } 6582393Syz155240 6593448Sdh155122 if (ifs->ifs_fr_authpkts != NULL) { 6603448Sdh155122 for (i = 0; i < ifs->ifs_fr_authsize; i++) { 6613448Sdh155122 m = ifs->ifs_fr_authpkts[i]; 6622393Syz155240 if (m != NULL) { 6632393Syz155240 FREE_MB_T(m); 6643448Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 6652393Syz155240 } 6662393Syz155240 } 6673448Sdh155122 KFREES(ifs->ifs_fr_authpkts, 6683448Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 6693448Sdh155122 ifs->ifs_fr_authpkts = NULL; 6702393Syz155240 } 6712393Syz155240 6723448Sdh155122 faep = &ifs->ifs_fae_list; 6732393Syz155240 while ((fae = *faep) != NULL) { 6742393Syz155240 *faep = fae->fae_next; 6752393Syz155240 KFREE(fae); 6762393Syz155240 } 6773448Sdh155122 ifs->ifs_ipauth = NULL; 6782393Syz155240 6793448Sdh155122 if (ifs->ifs_fr_authlist != NULL) { 6803448Sdh155122 for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 6812393Syz155240 if (fr->fr_ref == 1) { 6822393Syz155240 *frp = fr->fr_next; 6832393Syz155240 KFREE(fr); 6842393Syz155240 } else 6852393Syz155240 frp = &fr->fr_next; 6862393Syz155240 } 6872393Syz155240 } 6882393Syz155240 6893448Sdh155122 if (ifs->ifs_fr_auth_init == 1) { 6902393Syz155240 # if SOLARIS && defined(_KERNEL) 6913448Sdh155122 cv_destroy(&ifs->ifs_ipfauthwait); 6922393Syz155240 # endif 6933448Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_authmx); 6943448Sdh155122 RW_DESTROY(&ifs->ifs_ipf_auth); 6952393Syz155240 6963448Sdh155122 ifs->ifs_fr_auth_init = 0; 6972393Syz155240 } 6982393Syz155240 } 6992393Syz155240 7002393Syz155240 7012393Syz155240 /* 7022393Syz155240 * Slowly expire held auth records. Timeouts are set 7032393Syz155240 * in expectation of this being called twice per second. 7042393Syz155240 */ 7053448Sdh155122 void fr_authexpire(ifs) 7063448Sdh155122 ipf_stack_t *ifs; 7072393Syz155240 { 7082393Syz155240 register int i; 7092393Syz155240 register frauth_t *fra; 7102393Syz155240 register frauthent_t *fae, **faep; 7112393Syz155240 register frentry_t *fr, **frp; 7122393Syz155240 mb_t *m; 7132393Syz155240 SPL_INT(s); 7142393Syz155240 7153448Sdh155122 if (ifs->ifs_fr_auth_lock) 7162393Syz155240 return; 7172393Syz155240 7182393Syz155240 SPL_NET(s); 7193448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 7203448Sdh155122 for (i = 0, fra = ifs->ifs_fr_auth; i < ifs->ifs_fr_authsize; i++, fra++) { 7212393Syz155240 fra->fra_age--; 7223448Sdh155122 if ((fra->fra_age == 0) && (m = ifs->ifs_fr_authpkts[i])) { 7232393Syz155240 FREE_MB_T(m); 7243448Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 7253448Sdh155122 ifs->ifs_fr_auth[i].fra_index = -1; 7263448Sdh155122 ifs->ifs_fr_authstats.fas_expire++; 7273448Sdh155122 ifs->ifs_fr_authused--; 7282393Syz155240 } 7292393Syz155240 } 7302393Syz155240 7313448Sdh155122 for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 7322393Syz155240 fae->fae_age--; 7332393Syz155240 if (fae->fae_age == 0) { 7342393Syz155240 *faep = fae->fae_next; 7352393Syz155240 KFREE(fae); 7363448Sdh155122 ifs->ifs_fr_authstats.fas_expire++; 7372393Syz155240 } else 7382393Syz155240 faep = &fae->fae_next; 7392393Syz155240 } 7403448Sdh155122 if (ifs->ifs_fae_list != NULL) 7413448Sdh155122 ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 7422393Syz155240 else 7433448Sdh155122 ifs->ifs_ipauth = NULL; 7442393Syz155240 7453448Sdh155122 for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 7462393Syz155240 if (fr->fr_ref == 1) { 7472393Syz155240 *frp = fr->fr_next; 7482393Syz155240 KFREE(fr); 7492393Syz155240 } else 7502393Syz155240 frp = &fr->fr_next; 7512393Syz155240 } 7523448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 7532393Syz155240 SPL_X(s); 7542393Syz155240 } 7552393Syz155240 7563448Sdh155122 int fr_preauthcmd(cmd, fr, frptr, ifs) 7572393Syz155240 ioctlcmd_t cmd; 7582393Syz155240 frentry_t *fr, **frptr; 7593448Sdh155122 ipf_stack_t *ifs; 7602393Syz155240 { 7612393Syz155240 frauthent_t *fae, **faep; 7622393Syz155240 int error = 0; 7632393Syz155240 SPL_INT(s); 7642393Syz155240 7652393Syz155240 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 7662393Syz155240 return EIO; 7672393Syz155240 7683448Sdh155122 for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 7692393Syz155240 if (&fae->fae_fr == fr) 7702393Syz155240 break; 7712393Syz155240 else 7722393Syz155240 faep = &fae->fae_next; 7732393Syz155240 } 7742393Syz155240 7752393Syz155240 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 7762393Syz155240 if (fr == NULL || frptr == NULL) 7772393Syz155240 error = EINVAL; 7782393Syz155240 else if (fae == NULL) 7792393Syz155240 error = ESRCH; 7802393Syz155240 else { 7812393Syz155240 SPL_NET(s); 7823448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 7832393Syz155240 *faep = fae->fae_next; 7843448Sdh155122 if (ifs->ifs_ipauth == &fae->fae_fr) 7853448Sdh155122 ifs->ifs_ipauth = ifs->ifs_fae_list ? 7863448Sdh155122 &ifs->ifs_fae_list->fae_fr : NULL; 7873448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 7882393Syz155240 SPL_X(s); 7892393Syz155240 7902393Syz155240 KFREE(fae); 7912393Syz155240 } 7922393Syz155240 } else if (fr != NULL && frptr != NULL) { 7932393Syz155240 KMALLOC(fae, frauthent_t *); 7942393Syz155240 if (fae != NULL) { 7952393Syz155240 bcopy((char *)fr, (char *)&fae->fae_fr, 7962393Syz155240 sizeof(*fr)); 7972393Syz155240 SPL_NET(s); 7983448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 7993448Sdh155122 fae->fae_age = ifs->ifs_fr_defaultauthage; 8002393Syz155240 fae->fae_fr.fr_hits = 0; 8012393Syz155240 fae->fae_fr.fr_next = *frptr; 8023448Sdh155122 fae->fae_ref = 1; 8032393Syz155240 *frptr = &fae->fae_fr; 8042393Syz155240 fae->fae_next = *faep; 8052393Syz155240 *faep = fae; 8063448Sdh155122 ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 8073448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 8082393Syz155240 SPL_X(s); 8092393Syz155240 } else 8102393Syz155240 error = ENOMEM; 8112393Syz155240 } else 8122393Syz155240 error = EINVAL; 8132393Syz155240 return error; 8142393Syz155240 } 8152393Syz155240 8162393Syz155240 8172393Syz155240 /* 8182393Syz155240 * Flush held packets. 8192393Syz155240 * Must already be properly SPL'ed and Locked on &ipf_auth. 8202393Syz155240 * 8212393Syz155240 */ 8223448Sdh155122 int fr_authflush(ifs) 8233448Sdh155122 ipf_stack_t *ifs; 8242393Syz155240 { 8252393Syz155240 register int i, num_flushed; 8262393Syz155240 mb_t *m; 8272393Syz155240 8283448Sdh155122 if (ifs->ifs_fr_auth_lock) 8292393Syz155240 return -1; 8302393Syz155240 8312393Syz155240 num_flushed = 0; 8322393Syz155240 8333448Sdh155122 for (i = 0 ; i < ifs->ifs_fr_authsize; i++) { 8343448Sdh155122 m = ifs->ifs_fr_authpkts[i]; 8352393Syz155240 if (m != NULL) { 8362393Syz155240 FREE_MB_T(m); 8373448Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 8383448Sdh155122 ifs->ifs_fr_auth[i].fra_index = -1; 8392393Syz155240 /* perhaps add & use a flush counter inst.*/ 8403448Sdh155122 ifs->ifs_fr_authstats.fas_expire++; 8413448Sdh155122 ifs->ifs_fr_authused--; 8422393Syz155240 num_flushed++; 8432393Syz155240 } 8442393Syz155240 } 8452393Syz155240 8463448Sdh155122 ifs->ifs_fr_authstart = 0; 8473448Sdh155122 ifs->ifs_fr_authend = 0; 8483448Sdh155122 ifs->ifs_fr_authnext = 0; 8492393Syz155240 8502393Syz155240 return num_flushed; 8512393Syz155240 } 8523448Sdh155122 8533448Sdh155122 /* ------------------------------------------------------------------------ */ 8543448Sdh155122 /* Function: fr_authgeniter */ 8553448Sdh155122 /* Returns: int - 0 == success, else error */ 8563448Sdh155122 /* Parameters: token(I) - pointer to ipftoken structure */ 8573448Sdh155122 /* itp(I) - pointer to ipfgeniter structure */ 8583448Sdh155122 /* */ 8593448Sdh155122 /* ------------------------------------------------------------------------ */ 8603448Sdh155122 int fr_authgeniter(token, itp, ifs) 8613448Sdh155122 ipftoken_t *token; 8623448Sdh155122 ipfgeniter_t *itp; 8633448Sdh155122 ipf_stack_t *ifs; 8643448Sdh155122 { 8653448Sdh155122 frauthent_t *fae, *next, zero; 8663448Sdh155122 int error; 8673448Sdh155122 8683448Sdh155122 if (itp->igi_data == NULL) 8693448Sdh155122 return EFAULT; 8703448Sdh155122 8713448Sdh155122 if (itp->igi_type != IPFGENITER_AUTH) 8723448Sdh155122 return EINVAL; 8733448Sdh155122 8746518Sjojemann READ_ENTER(&ifs->ifs_ipf_auth); 8756518Sjojemann 8766518Sjojemann /* 8776518Sjojemann * Retrieve "previous" entry from token and find the next entry. 8786518Sjojemann */ 8793448Sdh155122 fae = token->ipt_data; 8803448Sdh155122 if (fae == NULL) { 8813448Sdh155122 next = ifs->ifs_fae_list; 8823448Sdh155122 } else { 8833448Sdh155122 next = fae->fae_next; 8843448Sdh155122 } 8853448Sdh155122 8866518Sjojemann /* 8876518Sjojemann * If we found an entry, add reference to it and update token. 8886518Sjojemann * Otherwise, zero out data to be returned and NULL out token. 8896518Sjojemann */ 8903448Sdh155122 if (next != NULL) { 8913448Sdh155122 ATOMIC_INC(next->fae_ref); 8926518Sjojemann token->ipt_data = next; 8933448Sdh155122 } else { 8943448Sdh155122 bzero(&zero, sizeof(zero)); 8953448Sdh155122 next = &zero; 8966518Sjojemann token->ipt_data = NULL; 8973448Sdh155122 } 8986518Sjojemann 8996518Sjojemann /* 9006518Sjojemann * Safe to release the lock now that we have a reference. 9016518Sjojemann */ 9023448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 9033448Sdh155122 9043448Sdh155122 /* 9056518Sjojemann * Copy out the data and clean up references and token as needed. 9063448Sdh155122 */ 9073448Sdh155122 error = COPYOUT(next, itp->igi_data, sizeof(*next)); 9083448Sdh155122 if (error != 0) 9093448Sdh155122 error = EFAULT; 9106518Sjojemann if (token->ipt_data == NULL) { 9116518Sjojemann ipf_freetoken(token, ifs); 9126518Sjojemann } else { 9136518Sjojemann if (fae != NULL) { 9146518Sjojemann WRITE_ENTER(&ifs->ifs_ipf_auth); 9156518Sjojemann fr_authderef(&fae); 9166518Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_auth); 9176518Sjojemann } 9186518Sjojemann if (next->fae_next == NULL) 9196518Sjojemann ipf_freetoken(token, ifs); 9206518Sjojemann } 9213448Sdh155122 return error; 9223448Sdh155122 } 9233448Sdh155122 9243448Sdh155122 9253448Sdh155122 void fr_authderef(faep) 9263448Sdh155122 frauthent_t **faep; 9273448Sdh155122 { 9283448Sdh155122 frauthent_t *fae; 9293448Sdh155122 9303448Sdh155122 fae = *faep; 9313448Sdh155122 *faep = NULL; 9323448Sdh155122 9333448Sdh155122 fae->fae_ref--; 9343448Sdh155122 if (fae->fae_ref == 0) { 9353448Sdh155122 KFREE(fae); 9363448Sdh155122 } 9373448Sdh155122 } 938