1ab25eeb5Syz155240 /* 2ab25eeb5Syz155240 * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 3ab25eeb5Syz155240 * 4ab25eeb5Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 5f4b3ec61Sdh155122 * 6*786c7074Sjojemann * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7381a2a9aSdr146992 * Use is subject to license terms. 8381a2a9aSdr146992 */ 9381a2a9aSdr146992 10381a2a9aSdr146992 #pragma ident "%Z%%M% %I% %E% SMI" 11381a2a9aSdr146992 12ab25eeb5Syz155240 #if defined(KERNEL) || defined(_KERNEL) 13ab25eeb5Syz155240 # undef KERNEL 14ab25eeb5Syz155240 # undef _KERNEL 15ab25eeb5Syz155240 # define KERNEL 1 16ab25eeb5Syz155240 # define _KERNEL 1 17ab25eeb5Syz155240 #endif 18ab25eeb5Syz155240 #include <sys/errno.h> 19ab25eeb5Syz155240 #include <sys/types.h> 20ab25eeb5Syz155240 #include <sys/param.h> 21ab25eeb5Syz155240 #include <sys/time.h> 22ab25eeb5Syz155240 #include <sys/file.h> 23ab25eeb5Syz155240 #if !defined(_KERNEL) 24ab25eeb5Syz155240 # include <stdio.h> 25ab25eeb5Syz155240 # include <stdlib.h> 26ab25eeb5Syz155240 # include <string.h> 27ab25eeb5Syz155240 # define _KERNEL 28ab25eeb5Syz155240 # ifdef __OpenBSD__ 29ab25eeb5Syz155240 struct file; 30ab25eeb5Syz155240 # endif 31ab25eeb5Syz155240 # include <sys/uio.h> 32ab25eeb5Syz155240 # undef _KERNEL 33ab25eeb5Syz155240 #endif 34ab25eeb5Syz155240 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 35ab25eeb5Syz155240 # include <sys/filio.h> 36ab25eeb5Syz155240 # include <sys/fcntl.h> 37ab25eeb5Syz155240 #else 38ab25eeb5Syz155240 # include <sys/ioctl.h> 39ab25eeb5Syz155240 #endif 40ab25eeb5Syz155240 #if !defined(linux) 41ab25eeb5Syz155240 # include <sys/protosw.h> 42ab25eeb5Syz155240 #endif 43ab25eeb5Syz155240 #include <sys/socket.h> 44ab25eeb5Syz155240 #if defined(_KERNEL) 45ab25eeb5Syz155240 # include <sys/systm.h> 46ab25eeb5Syz155240 # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 47ab25eeb5Syz155240 # include <sys/mbuf.h> 48ab25eeb5Syz155240 # endif 49ab25eeb5Syz155240 #endif 50ab25eeb5Syz155240 #if defined(__SVR4) || defined(__svr4__) 51ab25eeb5Syz155240 # include <sys/filio.h> 52ab25eeb5Syz155240 # include <sys/byteorder.h> 53ab25eeb5Syz155240 # ifdef _KERNEL 54ab25eeb5Syz155240 # include <sys/dditypes.h> 55ab25eeb5Syz155240 # endif 56ab25eeb5Syz155240 # include <sys/stream.h> 57ab25eeb5Syz155240 # include <sys/kmem.h> 58381a2a9aSdr146992 # include <sys/neti.h> 59ab25eeb5Syz155240 #endif 60ab25eeb5Syz155240 #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) 61ab25eeb5Syz155240 # include <sys/queue.h> 62ab25eeb5Syz155240 #endif 63ab25eeb5Syz155240 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 64ab25eeb5Syz155240 # include <machine/cpu.h> 65ab25eeb5Syz155240 #endif 66ab25eeb5Syz155240 #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 67ab25eeb5Syz155240 # include <sys/proc.h> 68ab25eeb5Syz155240 #endif 69ab25eeb5Syz155240 #include <net/if.h> 70ab25eeb5Syz155240 #ifdef sun 71ab25eeb5Syz155240 # include <net/af.h> 72ab25eeb5Syz155240 #endif 73ab25eeb5Syz155240 #include <net/route.h> 74ab25eeb5Syz155240 #include <netinet/in.h> 75ab25eeb5Syz155240 #include <netinet/in_systm.h> 76ab25eeb5Syz155240 #include <netinet/ip.h> 77ab25eeb5Syz155240 #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 78ab25eeb5Syz155240 # define KERNEL 79ab25eeb5Syz155240 # define _KERNEL 80ab25eeb5Syz155240 # define NOT_KERNEL 81ab25eeb5Syz155240 #endif 82ab25eeb5Syz155240 #if !defined(linux) 83ab25eeb5Syz155240 # include <netinet/ip_var.h> 84ab25eeb5Syz155240 #endif 85ab25eeb5Syz155240 #ifdef NOT_KERNEL 86ab25eeb5Syz155240 # undef _KERNEL 87ab25eeb5Syz155240 # undef KERNEL 88ab25eeb5Syz155240 #endif 89ab25eeb5Syz155240 #include <netinet/tcp.h> 90ab25eeb5Syz155240 #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 91ab25eeb5Syz155240 extern struct ifqueue ipintrq; /* ip packet input queue */ 92ab25eeb5Syz155240 #else 93ab25eeb5Syz155240 # if !defined(__hpux) && !defined(linux) 94ab25eeb5Syz155240 # if __FreeBSD_version >= 300000 95ab25eeb5Syz155240 # include <net/if_var.h> 96ab25eeb5Syz155240 # if __FreeBSD_version >= 500042 97ab25eeb5Syz155240 # define IF_QFULL _IF_QFULL 98ab25eeb5Syz155240 # define IF_DROP _IF_DROP 99ab25eeb5Syz155240 # endif /* __FreeBSD_version >= 500042 */ 100ab25eeb5Syz155240 # endif 101ab25eeb5Syz155240 # include <netinet/in_var.h> 102ab25eeb5Syz155240 # include <netinet/tcp_fsm.h> 103ab25eeb5Syz155240 # endif 104ab25eeb5Syz155240 #endif 105ab25eeb5Syz155240 #include <netinet/udp.h> 106ab25eeb5Syz155240 #include <netinet/ip_icmp.h> 107ab25eeb5Syz155240 #include "netinet/ip_compat.h" 108ab25eeb5Syz155240 #include <netinet/tcpip.h> 109f4b3ec61Sdh155122 #include "netinet/ipf_stack.h" 110ab25eeb5Syz155240 #include "netinet/ip_fil.h" 111ab25eeb5Syz155240 #include "netinet/ip_auth.h" 112ab25eeb5Syz155240 #if !defined(MENTAT) && !defined(linux) 113ab25eeb5Syz155240 # include <net/netisr.h> 114ab25eeb5Syz155240 # ifdef __FreeBSD__ 115ab25eeb5Syz155240 # include <machine/cpufunc.h> 116ab25eeb5Syz155240 # endif 117ab25eeb5Syz155240 #endif 118ab25eeb5Syz155240 #if (__FreeBSD_version >= 300000) 119ab25eeb5Syz155240 # include <sys/malloc.h> 120ab25eeb5Syz155240 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 121ab25eeb5Syz155240 # include <sys/libkern.h> 122ab25eeb5Syz155240 # include <sys/systm.h> 123ab25eeb5Syz155240 # endif 124ab25eeb5Syz155240 #endif 125ab25eeb5Syz155240 /* END OF INCLUDES */ 126ab25eeb5Syz155240 127ab25eeb5Syz155240 #if !defined(lint) 128ab25eeb5Syz155240 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $"; 129ab25eeb5Syz155240 #endif 130ab25eeb5Syz155240 131f4b3ec61Sdh155122 void fr_authderef __P((frauthent_t **)); 132f4b3ec61Sdh155122 int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 133ab25eeb5Syz155240 134ab25eeb5Syz155240 135f4b3ec61Sdh155122 int fr_authinit(ifs) 136f4b3ec61Sdh155122 ipf_stack_t *ifs; 137ab25eeb5Syz155240 { 138f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_fr_auth, frauth_t *, 139f4b3ec61Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 140f4b3ec61Sdh155122 if (ifs->ifs_fr_auth != NULL) 141f4b3ec61Sdh155122 bzero((char *)ifs->ifs_fr_auth, 142f4b3ec61Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 143ab25eeb5Syz155240 else 144ab25eeb5Syz155240 return -1; 145ab25eeb5Syz155240 146f4b3ec61Sdh155122 KMALLOCS(ifs->ifs_fr_authpkts, mb_t **, 147f4b3ec61Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 148f4b3ec61Sdh155122 if (ifs->ifs_fr_authpkts != NULL) 149f4b3ec61Sdh155122 bzero((char *)ifs->ifs_fr_authpkts, 150f4b3ec61Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 151ab25eeb5Syz155240 else 152ab25eeb5Syz155240 return -2; 153ab25eeb5Syz155240 154f4b3ec61Sdh155122 MUTEX_INIT(&ifs->ifs_ipf_authmx, "ipf auth log mutex"); 155f4b3ec61Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_auth, "ipf IP User-Auth rwlock"); 156ab25eeb5Syz155240 #if SOLARIS && defined(_KERNEL) 157f4b3ec61Sdh155122 cv_init(&ifs->ifs_ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 158ab25eeb5Syz155240 #endif 159ab25eeb5Syz155240 #if defined(linux) && defined(_KERNEL) 160ab25eeb5Syz155240 init_waitqueue_head(&fr_authnext_linux); 161ab25eeb5Syz155240 #endif 162ab25eeb5Syz155240 163f4b3ec61Sdh155122 ifs->ifs_fr_auth_init = 1; 164ab25eeb5Syz155240 165ab25eeb5Syz155240 return 0; 166ab25eeb5Syz155240 } 167ab25eeb5Syz155240 168ab25eeb5Syz155240 169ab25eeb5Syz155240 /* 170ab25eeb5Syz155240 * Check if a packet has authorization. If the packet is found to match an 171ab25eeb5Syz155240 * authorization result and that would result in a feedback loop (i.e. it 172ab25eeb5Syz155240 * will end up returning FR_AUTH) then return FR_BLOCK instead. 173ab25eeb5Syz155240 */ 174ab25eeb5Syz155240 frentry_t *fr_checkauth(fin, passp) 175ab25eeb5Syz155240 fr_info_t *fin; 176ab25eeb5Syz155240 u_32_t *passp; 177ab25eeb5Syz155240 { 178ab25eeb5Syz155240 frentry_t *fr; 179ab25eeb5Syz155240 frauth_t *fra; 180ab25eeb5Syz155240 u_32_t pass; 181ab25eeb5Syz155240 u_short id; 182ab25eeb5Syz155240 ip_t *ip; 183ab25eeb5Syz155240 int i; 184f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 185ab25eeb5Syz155240 186f4b3ec61Sdh155122 if (ifs->ifs_fr_auth_lock || !ifs->ifs_fr_authused) 187ab25eeb5Syz155240 return NULL; 188ab25eeb5Syz155240 189ab25eeb5Syz155240 ip = fin->fin_ip; 190ab25eeb5Syz155240 id = ip->ip_id; 191ab25eeb5Syz155240 192f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_auth); 193f4b3ec61Sdh155122 for (i = ifs->ifs_fr_authstart; i != ifs->ifs_fr_authend; ) { 194ab25eeb5Syz155240 /* 195ab25eeb5Syz155240 * index becomes -2 only after an SIOCAUTHW. Check this in 196ab25eeb5Syz155240 * case the same packet gets sent again and it hasn't yet been 197ab25eeb5Syz155240 * auth'd. 198ab25eeb5Syz155240 */ 199f4b3ec61Sdh155122 fra = ifs->ifs_fr_auth + i; 200ab25eeb5Syz155240 if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 201ab25eeb5Syz155240 !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 202ab25eeb5Syz155240 /* 203ab25eeb5Syz155240 * Avoid feedback loop. 204ab25eeb5Syz155240 */ 205ab25eeb5Syz155240 if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 206ab25eeb5Syz155240 pass = FR_BLOCK; 207ab25eeb5Syz155240 /* 208ab25eeb5Syz155240 * Create a dummy rule for the stateful checking to 209ab25eeb5Syz155240 * use and return. Zero out any values we don't 210ab25eeb5Syz155240 * trust from userland! 211ab25eeb5Syz155240 */ 212ab25eeb5Syz155240 if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 213ab25eeb5Syz155240 (fin->fin_flx & FI_FRAG))) { 214ab25eeb5Syz155240 KMALLOC(fr, frentry_t *); 215ab25eeb5Syz155240 if (fr) { 216ab25eeb5Syz155240 bcopy((char *)fra->fra_info.fin_fr, 217ab25eeb5Syz155240 (char *)fr, sizeof(*fr)); 218ab25eeb5Syz155240 fr->fr_grp = NULL; 219ab25eeb5Syz155240 fr->fr_ifa = fin->fin_ifp; 220ab25eeb5Syz155240 fr->fr_func = NULL; 221ab25eeb5Syz155240 fr->fr_ref = 1; 222ab25eeb5Syz155240 fr->fr_flags = pass; 223ab25eeb5Syz155240 fr->fr_ifas[1] = NULL; 224ab25eeb5Syz155240 fr->fr_ifas[2] = NULL; 225ab25eeb5Syz155240 fr->fr_ifas[3] = NULL; 226ab25eeb5Syz155240 } 227ab25eeb5Syz155240 } else 228ab25eeb5Syz155240 fr = fra->fra_info.fin_fr; 229ab25eeb5Syz155240 fin->fin_fr = fr; 230f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 231f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 232ab25eeb5Syz155240 if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 233f4b3ec61Sdh155122 fr->fr_next = ifs->ifs_fr_authlist; 234f4b3ec61Sdh155122 ifs->ifs_fr_authlist = fr; 235ab25eeb5Syz155240 } 236f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_hits++; 237ab25eeb5Syz155240 fra->fra_index = -1; 238f4b3ec61Sdh155122 ifs->ifs_fr_authused--; 239f4b3ec61Sdh155122 if (i == ifs->ifs_fr_authstart) { 240ab25eeb5Syz155240 while (fra->fra_index == -1) { 241ab25eeb5Syz155240 i++; 242ab25eeb5Syz155240 fra++; 243f4b3ec61Sdh155122 if (i == ifs->ifs_fr_authsize) { 244ab25eeb5Syz155240 i = 0; 245f4b3ec61Sdh155122 fra = ifs->ifs_fr_auth; 246ab25eeb5Syz155240 } 247f4b3ec61Sdh155122 ifs->ifs_fr_authstart = i; 248f4b3ec61Sdh155122 if (i == ifs->ifs_fr_authend) 249ab25eeb5Syz155240 break; 250ab25eeb5Syz155240 } 251f4b3ec61Sdh155122 if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 252f4b3ec61Sdh155122 ifs->ifs_fr_authnext = 0; 253f4b3ec61Sdh155122 ifs->ifs_fr_authstart = 0; 254f4b3ec61Sdh155122 ifs->ifs_fr_authend = 0; 255ab25eeb5Syz155240 } 256ab25eeb5Syz155240 } 257f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 258ab25eeb5Syz155240 if (passp != NULL) 259ab25eeb5Syz155240 *passp = pass; 260f4b3ec61Sdh155122 ATOMIC_INC64(ifs->ifs_fr_authstats.fas_hits); 261ab25eeb5Syz155240 return fr; 262ab25eeb5Syz155240 } 263ab25eeb5Syz155240 i++; 264f4b3ec61Sdh155122 if (i == ifs->ifs_fr_authsize) 265ab25eeb5Syz155240 i = 0; 266ab25eeb5Syz155240 } 267f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_miss++; 268f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 269f4b3ec61Sdh155122 ATOMIC_INC64(ifs->ifs_fr_authstats.fas_miss); 270ab25eeb5Syz155240 return NULL; 271ab25eeb5Syz155240 } 272ab25eeb5Syz155240 273ab25eeb5Syz155240 274ab25eeb5Syz155240 /* 275ab25eeb5Syz155240 * Check if we have room in the auth array to hold details for another packet. 276ab25eeb5Syz155240 * If we do, store it and wake up any user programs which are waiting to 277ab25eeb5Syz155240 * hear about these events. 278ab25eeb5Syz155240 */ 279ab25eeb5Syz155240 int fr_newauth(m, fin) 280ab25eeb5Syz155240 mb_t *m; 281ab25eeb5Syz155240 fr_info_t *fin; 282ab25eeb5Syz155240 { 283ab25eeb5Syz155240 #if defined(_KERNEL) && defined(MENTAT) 284ab25eeb5Syz155240 qpktinfo_t *qpi = fin->fin_qpi; 285ab25eeb5Syz155240 #endif 286ab25eeb5Syz155240 frauth_t *fra; 287ab25eeb5Syz155240 #if !defined(sparc) && !defined(m68k) 288ab25eeb5Syz155240 ip_t *ip; 289ab25eeb5Syz155240 #endif 290ab25eeb5Syz155240 int i; 291f4b3ec61Sdh155122 ipf_stack_t *ifs = fin->fin_ifs; 292ab25eeb5Syz155240 293f4b3ec61Sdh155122 if (ifs->ifs_fr_auth_lock) 294ab25eeb5Syz155240 return 0; 295ab25eeb5Syz155240 296f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 297f4b3ec61Sdh155122 if (ifs->ifs_fr_authstart > ifs->ifs_fr_authend) { 298f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_nospace++; 299f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 300ab25eeb5Syz155240 return 0; 301ab25eeb5Syz155240 } else { 302f4b3ec61Sdh155122 if (ifs->ifs_fr_authused == ifs->ifs_fr_authsize) { 303f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_nospace++; 304f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 305ab25eeb5Syz155240 return 0; 306ab25eeb5Syz155240 } 307ab25eeb5Syz155240 } 308ab25eeb5Syz155240 309f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_added++; 310f4b3ec61Sdh155122 ifs->ifs_fr_authused++; 311f4b3ec61Sdh155122 i = ifs->ifs_fr_authend++; 312f4b3ec61Sdh155122 if (ifs->ifs_fr_authend == ifs->ifs_fr_authsize) 313f4b3ec61Sdh155122 ifs->ifs_fr_authend = 0; 314f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 315ab25eeb5Syz155240 316f4b3ec61Sdh155122 fra = ifs->ifs_fr_auth + i; 317ab25eeb5Syz155240 fra->fra_index = i; 318ab25eeb5Syz155240 fra->fra_pass = 0; 319f4b3ec61Sdh155122 fra->fra_age = ifs->ifs_fr_defaultauthage; 320ab25eeb5Syz155240 bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 321ab25eeb5Syz155240 #if !defined(sparc) && !defined(m68k) 322ab25eeb5Syz155240 /* 323ab25eeb5Syz155240 * No need to copyback here as we want to undo the changes, not keep 324ab25eeb5Syz155240 * them. 325ab25eeb5Syz155240 */ 326ab25eeb5Syz155240 ip = fin->fin_ip; 327ab25eeb5Syz155240 # if defined(MENTAT) && defined(_KERNEL) 328ab25eeb5Syz155240 if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 329ab25eeb5Syz155240 # endif 330ab25eeb5Syz155240 { 331ab25eeb5Syz155240 register u_short bo; 332ab25eeb5Syz155240 333ab25eeb5Syz155240 bo = ip->ip_len; 334ab25eeb5Syz155240 ip->ip_len = htons(bo); 335ab25eeb5Syz155240 bo = ip->ip_off; 336ab25eeb5Syz155240 ip->ip_off = htons(bo); 337ab25eeb5Syz155240 } 338ab25eeb5Syz155240 #endif 339ab25eeb5Syz155240 #if SOLARIS && defined(_KERNEL) 340ab25eeb5Syz155240 m->b_rptr -= qpi->qpi_off; 341f4b3ec61Sdh155122 ifs->ifs_fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 342f4b3ec61Sdh155122 cv_signal(&ifs->ifs_ipfauthwait); 343ab25eeb5Syz155240 #else 344ab25eeb5Syz155240 # if defined(BSD) && !defined(sparc) && (BSD >= 199306) 345ab25eeb5Syz155240 if (!fin->fin_out) { 346ab25eeb5Syz155240 ip->ip_len = htons(ip->ip_len); 347ab25eeb5Syz155240 ip->ip_off = htons(ip->ip_off); 348ab25eeb5Syz155240 } 349ab25eeb5Syz155240 # endif 350f4b3ec61Sdh155122 ifs->ifs_fr_authpkts[i] = m; 351f4b3ec61Sdh155122 WAKEUP(&ifs->ifs_fr_authnext, 0); 352ab25eeb5Syz155240 #endif 353ab25eeb5Syz155240 return 1; 354ab25eeb5Syz155240 } 355ab25eeb5Syz155240 356ab25eeb5Syz155240 357f4b3ec61Sdh155122 int fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs) 358ab25eeb5Syz155240 caddr_t data; 359ab25eeb5Syz155240 ioctlcmd_t cmd; 360f4b3ec61Sdh155122 int mode,uid; 361f4b3ec61Sdh155122 void *ctx; 362f4b3ec61Sdh155122 ipf_stack_t *ifs; 363ab25eeb5Syz155240 { 364ab25eeb5Syz155240 mb_t *m; 365ab25eeb5Syz155240 #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 366ab25eeb5Syz155240 (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 367ab25eeb5Syz155240 struct ifqueue *ifq; 368ab25eeb5Syz155240 SPL_INT(s); 369ab25eeb5Syz155240 #endif 370ab25eeb5Syz155240 frauth_t auth, *au = &auth, *fra; 371ab25eeb5Syz155240 int i, error = 0, len; 372ab25eeb5Syz155240 char *t; 373381a2a9aSdr146992 net_data_t net_data_p; 374381a2a9aSdr146992 net_inject_t inj_data; 375381a2a9aSdr146992 int ret; 376ab25eeb5Syz155240 377ab25eeb5Syz155240 switch (cmd) 378ab25eeb5Syz155240 { 379f4b3ec61Sdh155122 case SIOCGENITER : 380f4b3ec61Sdh155122 { 381f4b3ec61Sdh155122 ipftoken_t *token; 382f4b3ec61Sdh155122 ipfgeniter_t iter; 383f4b3ec61Sdh155122 384f4b3ec61Sdh155122 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 385f4b3ec61Sdh155122 if (error != 0) 386f4b3ec61Sdh155122 break; 387f4b3ec61Sdh155122 388f4b3ec61Sdh155122 token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx, ifs); 389f4b3ec61Sdh155122 if (token != NULL) 390f4b3ec61Sdh155122 error = fr_authgeniter(token, &iter, ifs); 391f4b3ec61Sdh155122 else 392f4b3ec61Sdh155122 error = ESRCH; 393f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 394f4b3ec61Sdh155122 395f4b3ec61Sdh155122 break; 396f4b3ec61Sdh155122 } 397f4b3ec61Sdh155122 398ab25eeb5Syz155240 case SIOCSTLCK : 399ab25eeb5Syz155240 if (!(mode & FWRITE)) { 400ab25eeb5Syz155240 error = EPERM; 401ab25eeb5Syz155240 break; 402ab25eeb5Syz155240 } 403f4b3ec61Sdh155122 fr_lock(data, &ifs->ifs_fr_auth_lock); 404ab25eeb5Syz155240 break; 405ab25eeb5Syz155240 406ab25eeb5Syz155240 case SIOCATHST: 407f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_faelist = ifs->ifs_fae_list; 408f4b3ec61Sdh155122 error = fr_outobj(data, &ifs->ifs_fr_authstats, 409f4b3ec61Sdh155122 IPFOBJ_AUTHSTAT); 410ab25eeb5Syz155240 break; 411ab25eeb5Syz155240 412ab25eeb5Syz155240 case SIOCIPFFL: 413ab25eeb5Syz155240 SPL_NET(s); 414f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 415f4b3ec61Sdh155122 i = fr_authflush(ifs); 416f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 417ab25eeb5Syz155240 SPL_X(s); 418ab25eeb5Syz155240 error = copyoutptr((char *)&i, data, sizeof(i)); 419ab25eeb5Syz155240 break; 420ab25eeb5Syz155240 421ab25eeb5Syz155240 case SIOCAUTHW: 422ab25eeb5Syz155240 fr_authioctlloop: 423ab25eeb5Syz155240 error = fr_inobj(data, au, IPFOBJ_FRAUTH); 424f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_auth); 425f4b3ec61Sdh155122 if ((ifs->ifs_fr_authnext != ifs->ifs_fr_authend) && 426f4b3ec61Sdh155122 ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]) { 427f4b3ec61Sdh155122 error = fr_outobj(data, 428f4b3ec61Sdh155122 &ifs->ifs_fr_auth[ifs->ifs_fr_authnext], 429ab25eeb5Syz155240 IPFOBJ_FRAUTH); 430ab25eeb5Syz155240 if (auth.fra_len != 0 && auth.fra_buf != NULL) { 431ab25eeb5Syz155240 /* 432ab25eeb5Syz155240 * Copy packet contents out to user space if 433ab25eeb5Syz155240 * requested. Bail on an error. 434ab25eeb5Syz155240 */ 435f4b3ec61Sdh155122 m = ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]; 436ab25eeb5Syz155240 len = MSGDSIZE(m); 437ab25eeb5Syz155240 if (len > auth.fra_len) 438ab25eeb5Syz155240 len = auth.fra_len; 439ab25eeb5Syz155240 auth.fra_len = len; 440ab25eeb5Syz155240 for (t = auth.fra_buf; m && (len > 0); ) { 441ab25eeb5Syz155240 i = MIN(M_LEN(m), len); 442ab25eeb5Syz155240 error = copyoutptr(MTOD(m, char *), 443ab25eeb5Syz155240 t, i); 444ab25eeb5Syz155240 len -= i; 445ab25eeb5Syz155240 t += i; 446ab25eeb5Syz155240 if (error != 0) 447ab25eeb5Syz155240 break; 448ab25eeb5Syz155240 } 449ab25eeb5Syz155240 } 450f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 451ab25eeb5Syz155240 if (error != 0) 452ab25eeb5Syz155240 break; 453ab25eeb5Syz155240 SPL_NET(s); 454f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 455f4b3ec61Sdh155122 ifs->ifs_fr_authnext++; 456f4b3ec61Sdh155122 if (ifs->ifs_fr_authnext == ifs->ifs_fr_authsize) 457f4b3ec61Sdh155122 ifs->ifs_fr_authnext = 0; 458f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 459ab25eeb5Syz155240 SPL_X(s); 460ab25eeb5Syz155240 return 0; 461ab25eeb5Syz155240 } 462f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 463ab25eeb5Syz155240 /* 464ab25eeb5Syz155240 * We exit ipf_global here because a program that enters in 465ab25eeb5Syz155240 * here will have a lock on it and goto sleep having this lock. 466ab25eeb5Syz155240 * If someone were to do an 'ipf -D' the system would then 467ab25eeb5Syz155240 * deadlock. The catch with releasing it here is that the 468ab25eeb5Syz155240 * caller of this function expects it to be held when we 469ab25eeb5Syz155240 * return so we have to reacquire it in here. 470ab25eeb5Syz155240 */ 471f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 472ab25eeb5Syz155240 473f4b3ec61Sdh155122 MUTEX_ENTER(&ifs->ifs_ipf_authmx); 474ab25eeb5Syz155240 #ifdef _KERNEL 475ab25eeb5Syz155240 # if SOLARIS 476ab25eeb5Syz155240 error = 0; 477f4b3ec61Sdh155122 if (!cv_wait_sig(&ifs->ifs_ipfauthwait, &ifs->ifs_ipf_authmx.ipf_lk)) 478ab25eeb5Syz155240 error = EINTR; 479ab25eeb5Syz155240 # else /* SOLARIS */ 480ab25eeb5Syz155240 # ifdef __hpux 481ab25eeb5Syz155240 { 482ab25eeb5Syz155240 lock_t *l; 483ab25eeb5Syz155240 484f4b3ec61Sdh155122 l = get_sleep_lock(&ifs->ifs_fr_authnext); 485f4b3ec61Sdh155122 error = sleep(&ifs->ifs_fr_authnext, PZERO+1); 486ab25eeb5Syz155240 spinunlock(l); 487ab25eeb5Syz155240 } 488ab25eeb5Syz155240 # else 489ab25eeb5Syz155240 # ifdef __osf__ 490f4b3ec61Sdh155122 error = mpsleep(&ifs->ifs_fr_authnext, PSUSP|PCATCH, 491f4b3ec61Sdh155122 "fr_authnext", 0, 492f4b3ec61Sdh155122 &ifs->ifs_ipf_authmx, MS_LOCK_SIMPLE); 493ab25eeb5Syz155240 # else 494f4b3ec61Sdh155122 error = SLEEP(&ifs->ifs_fr_authnext, "fr_authnext"); 495ab25eeb5Syz155240 # endif /* __osf__ */ 496ab25eeb5Syz155240 # endif /* __hpux */ 497ab25eeb5Syz155240 # endif /* SOLARIS */ 498ab25eeb5Syz155240 #endif 499f4b3ec61Sdh155122 MUTEX_EXIT(&ifs->ifs_ipf_authmx); 500f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_global); 501ab25eeb5Syz155240 if (error == 0) { 502f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_auth); 503ab25eeb5Syz155240 goto fr_authioctlloop; 504ab25eeb5Syz155240 } 505ab25eeb5Syz155240 break; 506ab25eeb5Syz155240 507ab25eeb5Syz155240 case SIOCAUTHR: 508ab25eeb5Syz155240 error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 509ab25eeb5Syz155240 if (error != 0) 510ab25eeb5Syz155240 return error; 511ab25eeb5Syz155240 SPL_NET(s); 512f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 513ab25eeb5Syz155240 i = au->fra_index; 514f4b3ec61Sdh155122 fra = ifs->ifs_fr_auth + i; 515f4b3ec61Sdh155122 if ((i < 0) || (i >= ifs->ifs_fr_authsize) || 516ab25eeb5Syz155240 (fra->fra_info.fin_id != au->fra_info.fin_id)) { 517f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 518ab25eeb5Syz155240 SPL_X(s); 519ab25eeb5Syz155240 return ESRCH; 520ab25eeb5Syz155240 } 521f4b3ec61Sdh155122 m = ifs->ifs_fr_authpkts[i]; 522ab25eeb5Syz155240 fra->fra_index = -2; 523ab25eeb5Syz155240 fra->fra_pass = au->fra_pass; 524f4b3ec61Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 525f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 526ab25eeb5Syz155240 #ifdef _KERNEL 527381a2a9aSdr146992 if (fra->fra_info.fin_v == 4) { 528f4b3ec61Sdh155122 net_data_p = ifs->ifs_ipf_ipv4; 529381a2a9aSdr146992 } else if (fra->fra_info.fin_v == 6) { 530f4b3ec61Sdh155122 net_data_p = ifs->ifs_ipf_ipv6; 531381a2a9aSdr146992 } else { 532381a2a9aSdr146992 return (-1); 533381a2a9aSdr146992 } 534381a2a9aSdr146992 535381a2a9aSdr146992 /* 536381a2a9aSdr146992 * We're putting the packet back on the same interface 537381a2a9aSdr146992 * queue that it was originally seen on so that it can 538381a2a9aSdr146992 * progress through the system properly, with the result 539381a2a9aSdr146992 * of the auth check done. 540381a2a9aSdr146992 */ 541381a2a9aSdr146992 inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp; 542381a2a9aSdr146992 543ab25eeb5Syz155240 if ((m != NULL) && (au->fra_info.fin_out != 0)) { 544ab25eeb5Syz155240 # ifdef MENTAT 545381a2a9aSdr146992 inj_data.ni_packet = m; 546381a2a9aSdr146992 ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data); 547381a2a9aSdr146992 548381a2a9aSdr146992 if (ret < 0) 549f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_sendfail++; 550381a2a9aSdr146992 else 551f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_sendok++; 552ab25eeb5Syz155240 # else /* MENTAT */ 553ab25eeb5Syz155240 # if defined(linux) || defined(AIX) 554ab25eeb5Syz155240 # else 555ab25eeb5Syz155240 # if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ 556ab25eeb5Syz155240 (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \ 557ab25eeb5Syz155240 (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) 558ab25eeb5Syz155240 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, 559ab25eeb5Syz155240 NULL); 560ab25eeb5Syz155240 # else 561ab25eeb5Syz155240 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 562ab25eeb5Syz155240 # endif 563ab25eeb5Syz155240 if (error != 0) 564f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_sendfail++; 565ab25eeb5Syz155240 else 566f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_sendok++; 567381a2a9aSdr146992 # endif /* Linux */ 568381a2a9aSdr146992 # endif /* MENTAT */ 569ab25eeb5Syz155240 } else if (m) { 570ab25eeb5Syz155240 # ifdef MENTAT 571381a2a9aSdr146992 inj_data.ni_packet = m; 572381a2a9aSdr146992 ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data); 573ab25eeb5Syz155240 # else /* MENTAT */ 574ab25eeb5Syz155240 # if defined(linux) || defined(AIX) 575ab25eeb5Syz155240 # else 576ab25eeb5Syz155240 # if (__FreeBSD_version >= 501000) 577ab25eeb5Syz155240 netisr_dispatch(NETISR_IP, m); 578ab25eeb5Syz155240 # else 579ab25eeb5Syz155240 # if (IRIX >= 60516) 580ab25eeb5Syz155240 ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; 581ab25eeb5Syz155240 # else 582ab25eeb5Syz155240 ifq = &ipintrq; 583ab25eeb5Syz155240 # endif 584ab25eeb5Syz155240 if (IF_QFULL(ifq)) { 585ab25eeb5Syz155240 IF_DROP(ifq); 586ab25eeb5Syz155240 FREE_MB_T(m); 587ab25eeb5Syz155240 error = ENOBUFS; 588ab25eeb5Syz155240 } else { 589ab25eeb5Syz155240 IF_ENQUEUE(ifq, m); 590ab25eeb5Syz155240 # if IRIX < 60500 591ab25eeb5Syz155240 schednetisr(NETISR_IP); 592ab25eeb5Syz155240 # endif 593ab25eeb5Syz155240 } 594ab25eeb5Syz155240 # endif 595ab25eeb5Syz155240 # endif /* Linux */ 596ab25eeb5Syz155240 # endif /* MENTAT */ 597ab25eeb5Syz155240 if (error != 0) 598f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_quefail++; 599ab25eeb5Syz155240 else 600f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_queok++; 601ab25eeb5Syz155240 } else 602ab25eeb5Syz155240 error = EINVAL; 603ab25eeb5Syz155240 # ifdef MENTAT 604ab25eeb5Syz155240 if (error != 0) 605ab25eeb5Syz155240 error = EINVAL; 606ab25eeb5Syz155240 # else /* MENTAT */ 607ab25eeb5Syz155240 /* 608ab25eeb5Syz155240 * If we experience an error which will result in the packet 609ab25eeb5Syz155240 * not being processed, make sure we advance to the next one. 610ab25eeb5Syz155240 */ 611ab25eeb5Syz155240 if (error == ENOBUFS) { 612f4b3ec61Sdh155122 ifs->ifs_fr_authused--; 613ab25eeb5Syz155240 fra->fra_index = -1; 614ab25eeb5Syz155240 fra->fra_pass = 0; 615f4b3ec61Sdh155122 if (i == ifs->ifs_fr_authstart) { 616ab25eeb5Syz155240 while (fra->fra_index == -1) { 617ab25eeb5Syz155240 i++; 618f4b3ec61Sdh155122 if (i == ifs->ifs_fr_authsize) 619ab25eeb5Syz155240 i = 0; 620f4b3ec61Sdh155122 ifs->ifs_fr_authstart = i; 621f4b3ec61Sdh155122 if (i == ifs->ifs_fr_authend) 622ab25eeb5Syz155240 break; 623ab25eeb5Syz155240 } 624f4b3ec61Sdh155122 if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 625f4b3ec61Sdh155122 ifs->ifs_fr_authnext = 0; 626f4b3ec61Sdh155122 ifs->ifs_fr_authstart = 0; 627f4b3ec61Sdh155122 ifs->ifs_fr_authend = 0; 628ab25eeb5Syz155240 } 629ab25eeb5Syz155240 } 630ab25eeb5Syz155240 } 631ab25eeb5Syz155240 # endif /* MENTAT */ 632ab25eeb5Syz155240 #endif /* _KERNEL */ 633ab25eeb5Syz155240 SPL_X(s); 634ab25eeb5Syz155240 break; 635ab25eeb5Syz155240 636ab25eeb5Syz155240 default : 637ab25eeb5Syz155240 error = EINVAL; 638ab25eeb5Syz155240 break; 639ab25eeb5Syz155240 } 640ab25eeb5Syz155240 return error; 641ab25eeb5Syz155240 } 642ab25eeb5Syz155240 643ab25eeb5Syz155240 644ab25eeb5Syz155240 /* 645ab25eeb5Syz155240 * Free all network buffer memory used to keep saved packets. 646ab25eeb5Syz155240 */ 647f4b3ec61Sdh155122 void fr_authunload(ifs) 648f4b3ec61Sdh155122 ipf_stack_t *ifs; 649ab25eeb5Syz155240 { 650ab25eeb5Syz155240 register int i; 651ab25eeb5Syz155240 register frauthent_t *fae, **faep; 652ab25eeb5Syz155240 frentry_t *fr, **frp; 653ab25eeb5Syz155240 mb_t *m; 654ab25eeb5Syz155240 655f4b3ec61Sdh155122 if (ifs->ifs_fr_auth != NULL) { 656f4b3ec61Sdh155122 KFREES(ifs->ifs_fr_auth, 657f4b3ec61Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 658f4b3ec61Sdh155122 ifs->ifs_fr_auth = NULL; 659ab25eeb5Syz155240 } 660ab25eeb5Syz155240 661f4b3ec61Sdh155122 if (ifs->ifs_fr_authpkts != NULL) { 662f4b3ec61Sdh155122 for (i = 0; i < ifs->ifs_fr_authsize; i++) { 663f4b3ec61Sdh155122 m = ifs->ifs_fr_authpkts[i]; 664ab25eeb5Syz155240 if (m != NULL) { 665ab25eeb5Syz155240 FREE_MB_T(m); 666f4b3ec61Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 667ab25eeb5Syz155240 } 668ab25eeb5Syz155240 } 669f4b3ec61Sdh155122 KFREES(ifs->ifs_fr_authpkts, 670f4b3ec61Sdh155122 ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 671f4b3ec61Sdh155122 ifs->ifs_fr_authpkts = NULL; 672ab25eeb5Syz155240 } 673ab25eeb5Syz155240 674f4b3ec61Sdh155122 faep = &ifs->ifs_fae_list; 675ab25eeb5Syz155240 while ((fae = *faep) != NULL) { 676ab25eeb5Syz155240 *faep = fae->fae_next; 677ab25eeb5Syz155240 KFREE(fae); 678ab25eeb5Syz155240 } 679f4b3ec61Sdh155122 ifs->ifs_ipauth = NULL; 680ab25eeb5Syz155240 681f4b3ec61Sdh155122 if (ifs->ifs_fr_authlist != NULL) { 682f4b3ec61Sdh155122 for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 683ab25eeb5Syz155240 if (fr->fr_ref == 1) { 684ab25eeb5Syz155240 *frp = fr->fr_next; 685ab25eeb5Syz155240 KFREE(fr); 686ab25eeb5Syz155240 } else 687ab25eeb5Syz155240 frp = &fr->fr_next; 688ab25eeb5Syz155240 } 689ab25eeb5Syz155240 } 690ab25eeb5Syz155240 691f4b3ec61Sdh155122 if (ifs->ifs_fr_auth_init == 1) { 692ab25eeb5Syz155240 # if SOLARIS && defined(_KERNEL) 693f4b3ec61Sdh155122 cv_destroy(&ifs->ifs_ipfauthwait); 694ab25eeb5Syz155240 # endif 695f4b3ec61Sdh155122 MUTEX_DESTROY(&ifs->ifs_ipf_authmx); 696f4b3ec61Sdh155122 RW_DESTROY(&ifs->ifs_ipf_auth); 697ab25eeb5Syz155240 698f4b3ec61Sdh155122 ifs->ifs_fr_auth_init = 0; 699ab25eeb5Syz155240 } 700ab25eeb5Syz155240 } 701ab25eeb5Syz155240 702ab25eeb5Syz155240 703ab25eeb5Syz155240 /* 704ab25eeb5Syz155240 * Slowly expire held auth records. Timeouts are set 705ab25eeb5Syz155240 * in expectation of this being called twice per second. 706ab25eeb5Syz155240 */ 707f4b3ec61Sdh155122 void fr_authexpire(ifs) 708f4b3ec61Sdh155122 ipf_stack_t *ifs; 709ab25eeb5Syz155240 { 710ab25eeb5Syz155240 register int i; 711ab25eeb5Syz155240 register frauth_t *fra; 712ab25eeb5Syz155240 register frauthent_t *fae, **faep; 713ab25eeb5Syz155240 register frentry_t *fr, **frp; 714ab25eeb5Syz155240 mb_t *m; 715ab25eeb5Syz155240 SPL_INT(s); 716ab25eeb5Syz155240 717f4b3ec61Sdh155122 if (ifs->ifs_fr_auth_lock) 718ab25eeb5Syz155240 return; 719ab25eeb5Syz155240 720ab25eeb5Syz155240 SPL_NET(s); 721f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 722f4b3ec61Sdh155122 for (i = 0, fra = ifs->ifs_fr_auth; i < ifs->ifs_fr_authsize; i++, fra++) { 723ab25eeb5Syz155240 fra->fra_age--; 724f4b3ec61Sdh155122 if ((fra->fra_age == 0) && (m = ifs->ifs_fr_authpkts[i])) { 725ab25eeb5Syz155240 FREE_MB_T(m); 726f4b3ec61Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 727f4b3ec61Sdh155122 ifs->ifs_fr_auth[i].fra_index = -1; 728f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_expire++; 729f4b3ec61Sdh155122 ifs->ifs_fr_authused--; 730ab25eeb5Syz155240 } 731ab25eeb5Syz155240 } 732ab25eeb5Syz155240 733f4b3ec61Sdh155122 for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 734ab25eeb5Syz155240 fae->fae_age--; 735ab25eeb5Syz155240 if (fae->fae_age == 0) { 736ab25eeb5Syz155240 *faep = fae->fae_next; 737ab25eeb5Syz155240 KFREE(fae); 738f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_expire++; 739ab25eeb5Syz155240 } else 740ab25eeb5Syz155240 faep = &fae->fae_next; 741ab25eeb5Syz155240 } 742f4b3ec61Sdh155122 if (ifs->ifs_fae_list != NULL) 743f4b3ec61Sdh155122 ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 744ab25eeb5Syz155240 else 745f4b3ec61Sdh155122 ifs->ifs_ipauth = NULL; 746ab25eeb5Syz155240 747f4b3ec61Sdh155122 for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 748ab25eeb5Syz155240 if (fr->fr_ref == 1) { 749ab25eeb5Syz155240 *frp = fr->fr_next; 750ab25eeb5Syz155240 KFREE(fr); 751ab25eeb5Syz155240 } else 752ab25eeb5Syz155240 frp = &fr->fr_next; 753ab25eeb5Syz155240 } 754f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 755ab25eeb5Syz155240 SPL_X(s); 756ab25eeb5Syz155240 } 757ab25eeb5Syz155240 758f4b3ec61Sdh155122 int fr_preauthcmd(cmd, fr, frptr, ifs) 759ab25eeb5Syz155240 ioctlcmd_t cmd; 760ab25eeb5Syz155240 frentry_t *fr, **frptr; 761f4b3ec61Sdh155122 ipf_stack_t *ifs; 762ab25eeb5Syz155240 { 763ab25eeb5Syz155240 frauthent_t *fae, **faep; 764ab25eeb5Syz155240 int error = 0; 765ab25eeb5Syz155240 SPL_INT(s); 766ab25eeb5Syz155240 767ab25eeb5Syz155240 if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 768ab25eeb5Syz155240 return EIO; 769ab25eeb5Syz155240 770f4b3ec61Sdh155122 for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 771ab25eeb5Syz155240 if (&fae->fae_fr == fr) 772ab25eeb5Syz155240 break; 773ab25eeb5Syz155240 else 774ab25eeb5Syz155240 faep = &fae->fae_next; 775ab25eeb5Syz155240 } 776ab25eeb5Syz155240 777ab25eeb5Syz155240 if (cmd == (ioctlcmd_t)SIOCRMAFR) { 778ab25eeb5Syz155240 if (fr == NULL || frptr == NULL) 779ab25eeb5Syz155240 error = EINVAL; 780ab25eeb5Syz155240 else if (fae == NULL) 781ab25eeb5Syz155240 error = ESRCH; 782ab25eeb5Syz155240 else { 783ab25eeb5Syz155240 SPL_NET(s); 784f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 785ab25eeb5Syz155240 *faep = fae->fae_next; 786f4b3ec61Sdh155122 if (ifs->ifs_ipauth == &fae->fae_fr) 787f4b3ec61Sdh155122 ifs->ifs_ipauth = ifs->ifs_fae_list ? 788f4b3ec61Sdh155122 &ifs->ifs_fae_list->fae_fr : NULL; 789f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 790ab25eeb5Syz155240 SPL_X(s); 791ab25eeb5Syz155240 792ab25eeb5Syz155240 KFREE(fae); 793ab25eeb5Syz155240 } 794ab25eeb5Syz155240 } else if (fr != NULL && frptr != NULL) { 795ab25eeb5Syz155240 KMALLOC(fae, frauthent_t *); 796ab25eeb5Syz155240 if (fae != NULL) { 797ab25eeb5Syz155240 bcopy((char *)fr, (char *)&fae->fae_fr, 798ab25eeb5Syz155240 sizeof(*fr)); 799ab25eeb5Syz155240 SPL_NET(s); 800f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 801f4b3ec61Sdh155122 fae->fae_age = ifs->ifs_fr_defaultauthage; 802ab25eeb5Syz155240 fae->fae_fr.fr_hits = 0; 803ab25eeb5Syz155240 fae->fae_fr.fr_next = *frptr; 804f4b3ec61Sdh155122 fae->fae_ref = 1; 805ab25eeb5Syz155240 *frptr = &fae->fae_fr; 806ab25eeb5Syz155240 fae->fae_next = *faep; 807ab25eeb5Syz155240 *faep = fae; 808f4b3ec61Sdh155122 ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 809f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 810ab25eeb5Syz155240 SPL_X(s); 811ab25eeb5Syz155240 } else 812ab25eeb5Syz155240 error = ENOMEM; 813ab25eeb5Syz155240 } else 814ab25eeb5Syz155240 error = EINVAL; 815ab25eeb5Syz155240 return error; 816ab25eeb5Syz155240 } 817ab25eeb5Syz155240 818ab25eeb5Syz155240 819ab25eeb5Syz155240 /* 820ab25eeb5Syz155240 * Flush held packets. 821ab25eeb5Syz155240 * Must already be properly SPL'ed and Locked on &ipf_auth. 822ab25eeb5Syz155240 * 823ab25eeb5Syz155240 */ 824f4b3ec61Sdh155122 int fr_authflush(ifs) 825f4b3ec61Sdh155122 ipf_stack_t *ifs; 826ab25eeb5Syz155240 { 827ab25eeb5Syz155240 register int i, num_flushed; 828ab25eeb5Syz155240 mb_t *m; 829ab25eeb5Syz155240 830f4b3ec61Sdh155122 if (ifs->ifs_fr_auth_lock) 831ab25eeb5Syz155240 return -1; 832ab25eeb5Syz155240 833ab25eeb5Syz155240 num_flushed = 0; 834ab25eeb5Syz155240 835f4b3ec61Sdh155122 for (i = 0 ; i < ifs->ifs_fr_authsize; i++) { 836f4b3ec61Sdh155122 m = ifs->ifs_fr_authpkts[i]; 837ab25eeb5Syz155240 if (m != NULL) { 838ab25eeb5Syz155240 FREE_MB_T(m); 839f4b3ec61Sdh155122 ifs->ifs_fr_authpkts[i] = NULL; 840f4b3ec61Sdh155122 ifs->ifs_fr_auth[i].fra_index = -1; 841ab25eeb5Syz155240 /* perhaps add & use a flush counter inst.*/ 842f4b3ec61Sdh155122 ifs->ifs_fr_authstats.fas_expire++; 843f4b3ec61Sdh155122 ifs->ifs_fr_authused--; 844ab25eeb5Syz155240 num_flushed++; 845ab25eeb5Syz155240 } 846ab25eeb5Syz155240 } 847ab25eeb5Syz155240 848f4b3ec61Sdh155122 ifs->ifs_fr_authstart = 0; 849f4b3ec61Sdh155122 ifs->ifs_fr_authend = 0; 850f4b3ec61Sdh155122 ifs->ifs_fr_authnext = 0; 851ab25eeb5Syz155240 852ab25eeb5Syz155240 return num_flushed; 853ab25eeb5Syz155240 } 854f4b3ec61Sdh155122 855f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 856f4b3ec61Sdh155122 /* Function: fr_authgeniter */ 857f4b3ec61Sdh155122 /* Returns: int - 0 == success, else error */ 858f4b3ec61Sdh155122 /* Parameters: token(I) - pointer to ipftoken structure */ 859f4b3ec61Sdh155122 /* itp(I) - pointer to ipfgeniter structure */ 860f4b3ec61Sdh155122 /* */ 861f4b3ec61Sdh155122 /* ------------------------------------------------------------------------ */ 862f4b3ec61Sdh155122 int fr_authgeniter(token, itp, ifs) 863f4b3ec61Sdh155122 ipftoken_t *token; 864f4b3ec61Sdh155122 ipfgeniter_t *itp; 865f4b3ec61Sdh155122 ipf_stack_t *ifs; 866f4b3ec61Sdh155122 { 867f4b3ec61Sdh155122 frauthent_t *fae, *next, zero; 868f4b3ec61Sdh155122 int error; 869f4b3ec61Sdh155122 870f4b3ec61Sdh155122 if (itp->igi_data == NULL) 871f4b3ec61Sdh155122 return EFAULT; 872f4b3ec61Sdh155122 873f4b3ec61Sdh155122 if (itp->igi_type != IPFGENITER_AUTH) 874f4b3ec61Sdh155122 return EINVAL; 875f4b3ec61Sdh155122 876f4b3ec61Sdh155122 READ_ENTER(&ifs->ifs_ipf_auth); 877*786c7074Sjojemann 878*786c7074Sjojemann /* 879*786c7074Sjojemann * Retrieve "previous" entry from token and find the next entry. 880*786c7074Sjojemann */ 881*786c7074Sjojemann fae = token->ipt_data; 882f4b3ec61Sdh155122 if (fae == NULL) { 883f4b3ec61Sdh155122 next = ifs->ifs_fae_list; 884f4b3ec61Sdh155122 } else { 885f4b3ec61Sdh155122 next = fae->fae_next; 886f4b3ec61Sdh155122 } 887f4b3ec61Sdh155122 888f4b3ec61Sdh155122 /* 889*786c7074Sjojemann * If we found an entry, add reference to it and update token. 890*786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 891f4b3ec61Sdh155122 */ 892*786c7074Sjojemann if (next != NULL) { 893f4b3ec61Sdh155122 ATOMIC_INC(next->fae_ref); 894*786c7074Sjojemann token->ipt_data = next; 895f4b3ec61Sdh155122 } else { 896f4b3ec61Sdh155122 bzero(&zero, sizeof(zero)); 897f4b3ec61Sdh155122 next = &zero; 898*786c7074Sjojemann token->ipt_data = NULL; 899f4b3ec61Sdh155122 } 900*786c7074Sjojemann 901*786c7074Sjojemann /* 902*786c7074Sjojemann * Safe to release the lock now that we have a reference. 903*786c7074Sjojemann */ 904f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 905f4b3ec61Sdh155122 906f4b3ec61Sdh155122 /* 907*786c7074Sjojemann * Copy out the data and clean up references and token as needed. 908f4b3ec61Sdh155122 */ 909*786c7074Sjojemann error = COPYOUT(next, itp->igi_data, sizeof(*next)); 910*786c7074Sjojemann if (error != 0) 911*786c7074Sjojemann error = EFAULT; 912*786c7074Sjojemann if (token->ipt_data == NULL) { 913*786c7074Sjojemann ipf_freetoken(token, ifs); 914*786c7074Sjojemann } else { 915f4b3ec61Sdh155122 if (fae != NULL) { 916f4b3ec61Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_auth); 917f4b3ec61Sdh155122 fr_authderef(&fae); 918f4b3ec61Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_auth); 919f4b3ec61Sdh155122 } 920*786c7074Sjojemann if (next->fae_next == NULL) 921*786c7074Sjojemann ipf_freetoken(token, ifs); 922*786c7074Sjojemann } 923f4b3ec61Sdh155122 return error; 924f4b3ec61Sdh155122 } 925f4b3ec61Sdh155122 926f4b3ec61Sdh155122 927f4b3ec61Sdh155122 void fr_authderef(faep) 928f4b3ec61Sdh155122 frauthent_t **faep; 929f4b3ec61Sdh155122 { 930f4b3ec61Sdh155122 frauthent_t *fae; 931f4b3ec61Sdh155122 932f4b3ec61Sdh155122 fae = *faep; 933f4b3ec61Sdh155122 *faep = NULL; 934f4b3ec61Sdh155122 935f4b3ec61Sdh155122 fae->fae_ref--; 936f4b3ec61Sdh155122 if (fae->fae_ref == 0) { 937f4b3ec61Sdh155122 KFREE(fae); 938f4b3ec61Sdh155122 } 939f4b3ec61Sdh155122 } 940