1145522Sdarrenr/* $FreeBSD$ */ 2145522Sdarrenr 353642Sguido/* 4145522Sdarrenr * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 553642Sguido * 680482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 753642Sguido */ 8145522Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 9145522Sdarrenr# undef KERNEL 10145522Sdarrenr# undef _KERNEL 11145522Sdarrenr# define KERNEL 1 12145522Sdarrenr# define _KERNEL 1 1392685Sdarrenr#endif 1453642Sguido#include <sys/errno.h> 1553642Sguido#include <sys/types.h> 1653642Sguido#include <sys/param.h> 1753642Sguido#include <sys/time.h> 1853642Sguido#include <sys/file.h> 19145522Sdarrenr#if !defined(_KERNEL) 2053642Sguido# include <stdio.h> 2153642Sguido# include <stdlib.h> 2253642Sguido# include <string.h> 23145522Sdarrenr# define _KERNEL 24145522Sdarrenr# ifdef __OpenBSD__ 25145522Sdarrenrstruct file; 26145522Sdarrenr# endif 27145522Sdarrenr# include <sys/uio.h> 28145522Sdarrenr# undef _KERNEL 2953642Sguido#endif 30145522Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 220000) 3153642Sguido# include <sys/filio.h> 3253642Sguido# include <sys/fcntl.h> 3353642Sguido#else 3453642Sguido# include <sys/ioctl.h> 3553642Sguido#endif 36145522Sdarrenr#if !defined(linux) 3753642Sguido# include <sys/protosw.h> 3853642Sguido#endif 3953642Sguido#include <sys/socket.h> 40145522Sdarrenr#if defined(_KERNEL) 4153642Sguido# include <sys/systm.h> 42145522Sdarrenr# if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 4353642Sguido# include <sys/mbuf.h> 4453642Sguido# endif 45145522Sdarrenr#endif 46145522Sdarrenr#if defined(__SVR4) || defined(__svr4__) 4753642Sguido# include <sys/filio.h> 4853642Sguido# include <sys/byteorder.h> 4953642Sguido# ifdef _KERNEL 5053642Sguido# include <sys/dditypes.h> 5153642Sguido# endif 5253642Sguido# include <sys/stream.h> 5353642Sguido# include <sys/kmem.h> 5453642Sguido#endif 55153084Sru#if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199802) || \ 56173181Sdarrenr (defined(__FreeBSD_version) &&(__FreeBSD_version >= 400000)) 5753642Sguido# include <sys/queue.h> 5853642Sguido#endif 5953642Sguido#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 6053642Sguido# include <machine/cpu.h> 6153642Sguido#endif 62145522Sdarrenr#if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 63145522Sdarrenr# include <sys/proc.h> 64145522Sdarrenr#endif 6553642Sguido#include <net/if.h> 6653642Sguido#ifdef sun 6753642Sguido# include <net/af.h> 6853642Sguido#endif 6953642Sguido#include <net/route.h> 7053642Sguido#include <netinet/in.h> 7153642Sguido#include <netinet/in_systm.h> 7253642Sguido#include <netinet/ip.h> 73145522Sdarrenr#if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 7453642Sguido# define KERNEL 75145522Sdarrenr# define _KERNEL 7653642Sguido# define NOT_KERNEL 7753642Sguido#endif 78145522Sdarrenr#if !defined(linux) 7953642Sguido# include <netinet/ip_var.h> 8053642Sguido#endif 8153642Sguido#ifdef NOT_KERNEL 82145522Sdarrenr# undef _KERNEL 8353642Sguido# undef KERNEL 8453642Sguido#endif 8553642Sguido#include <netinet/tcp.h> 86145522Sdarrenr#if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 8780482Sdarrenrextern struct ifqueue ipintrq; /* ip packet input queue */ 8853642Sguido#else 89145522Sdarrenr# if !defined(__hpux) && !defined(linux) 9053642Sguido# if __FreeBSD_version >= 300000 9153642Sguido# include <net/if_var.h> 92145522Sdarrenr# if __FreeBSD_version >= 500042 93145522Sdarrenr# define IF_QFULL _IF_QFULL 94145522Sdarrenr# define IF_DROP _IF_DROP 95145522Sdarrenr# endif /* __FreeBSD_version >= 500042 */ 9653642Sguido# endif 9753642Sguido# include <netinet/in_var.h> 9853642Sguido# include <netinet/tcp_fsm.h> 9953642Sguido# endif 10053642Sguido#endif 10153642Sguido#include <netinet/udp.h> 10253642Sguido#include <netinet/ip_icmp.h> 10353642Sguido#include "netinet/ip_compat.h" 10453642Sguido#include <netinet/tcpip.h> 10553642Sguido#include "netinet/ip_fil.h" 10653642Sguido#include "netinet/ip_auth.h" 107145522Sdarrenr#if !defined(MENTAT) && !defined(linux) 10853642Sguido# include <net/netisr.h> 10953642Sguido# ifdef __FreeBSD__ 11053642Sguido# include <machine/cpufunc.h> 11153642Sguido# endif 11253642Sguido#endif 11353642Sguido#if (__FreeBSD_version >= 300000) 11453642Sguido# include <sys/malloc.h> 115145522Sdarrenr# if defined(_KERNEL) && !defined(IPFILTER_LKM) 11653642Sguido# include <sys/libkern.h> 11753642Sguido# include <sys/systm.h> 11853642Sguido# endif 11953642Sguido#endif 120145522Sdarrenr/* END OF INCLUDES */ 12153642Sguido 12280482Sdarrenr#if !defined(lint) 12380482Sdarrenrstatic const char rcsid[] = "@(#)$FreeBSD$"; 124172776Sdarrenr/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.24 2007/09/09 11:32:04 darrenr Exp $"; */ 12580482Sdarrenr#endif 12653642Sguido 12753642Sguido 128161356Sguido#if SOLARIS && defined(_KERNEL) 12953642Sguidoextern kcondvar_t ipfauthwait; 130161356Sguidoextern struct pollhead iplpollhead[IPL_LOGSIZE]; 131145522Sdarrenr#endif /* SOLARIS */ 132145522Sdarrenr#if defined(linux) && defined(_KERNEL) 133145522Sdarrenrwait_queue_head_t fr_authnext_linux; 13453642Sguido#endif 13553642Sguido 13653642Sguidoint fr_authsize = FR_NUMAUTH; 13753642Sguidoint fr_authused = 0; 13853642Sguidoint fr_defaultauthage = 600; 13960850Sdarrenrint fr_auth_lock = 0; 140145522Sdarrenrint fr_auth_init = 0; 14153642Sguidofr_authstat_t fr_authstats; 142145522Sdarrenrstatic frauth_t *fr_auth = NULL; 143145522Sdarrenrmb_t **fr_authpkts = NULL; 144145522Sdarrenrint fr_authstart = 0, fr_authend = 0, fr_authnext = 0; 145145522Sdarrenrfrauthent_t *fae_list = NULL; 14680482Sdarrenrfrentry_t *ipauth = NULL, 14780482Sdarrenr *fr_authlist = NULL; 14853642Sguido 149170268Sdarrenrvoid fr_authderef __P((frauthent_t **)); 150170268Sdarrenrint fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *)); 151170268Sdarrenrint fr_authreply __P((char *)); 152170268Sdarrenrint fr_authwait __P((char *)); 15353642Sguido 154170268Sdarrenr/* ------------------------------------------------------------------------ */ 155170268Sdarrenr/* Function: fr_authinit */ 156170268Sdarrenr/* Returns: int - 0 == success, else error */ 157170268Sdarrenr/* Parameters: None */ 158170268Sdarrenr/* */ 159170268Sdarrenr/* Allocate memory and initialise data structures used in handling auth */ 160170268Sdarrenr/* rules. */ 161170268Sdarrenr/* ------------------------------------------------------------------------ */ 162145522Sdarrenrint fr_authinit() 163145522Sdarrenr{ 164145522Sdarrenr KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); 165145522Sdarrenr if (fr_auth != NULL) 166145522Sdarrenr bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); 167145522Sdarrenr else 168145522Sdarrenr return -1; 169145522Sdarrenr 170145522Sdarrenr KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); 171145522Sdarrenr if (fr_authpkts != NULL) 172145522Sdarrenr bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 173145522Sdarrenr else 174145522Sdarrenr return -2; 175145522Sdarrenr 176145522Sdarrenr MUTEX_INIT(&ipf_authmx, "ipf auth log mutex"); 177145522Sdarrenr RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock"); 178145522Sdarrenr#if SOLARIS && defined(_KERNEL) 179145522Sdarrenr cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 180145522Sdarrenr#endif 181145522Sdarrenr#if defined(linux) && defined(_KERNEL) 182145522Sdarrenr init_waitqueue_head(&fr_authnext_linux); 183145522Sdarrenr#endif 184145522Sdarrenr 185145522Sdarrenr fr_auth_init = 1; 186145522Sdarrenr 187145522Sdarrenr return 0; 188145522Sdarrenr} 189145522Sdarrenr 190145522Sdarrenr 191170268Sdarrenr/* ------------------------------------------------------------------------ */ 192170268Sdarrenr/* Function: fr_checkauth */ 193170268Sdarrenr/* Returns: frentry_t* - pointer to ipf rule if match found, else NULL */ 194170268Sdarrenr/* Parameters: fin(I) - pointer to ipftoken structure */ 195170268Sdarrenr/* passp(I) - pointer to ipfgeniter structure */ 196170268Sdarrenr/* */ 197170268Sdarrenr/* Check if a packet has authorization. If the packet is found to match an */ 198170268Sdarrenr/* authorization result and that would result in a feedback loop (i.e. it */ 199170268Sdarrenr/* will end up returning FR_AUTH) then return FR_BLOCK instead. */ 200170268Sdarrenr/* ------------------------------------------------------------------------ */ 201145522Sdarrenrfrentry_t *fr_checkauth(fin, passp) 20253642Sguidofr_info_t *fin; 203145522Sdarrenru_32_t *passp; 20453642Sguido{ 20580482Sdarrenr frentry_t *fr; 20680482Sdarrenr frauth_t *fra; 20753642Sguido u_32_t pass; 208145522Sdarrenr u_short id; 209145522Sdarrenr ip_t *ip; 21053642Sguido int i; 21153642Sguido 21280482Sdarrenr if (fr_auth_lock || !fr_authused) 213145522Sdarrenr return NULL; 21460850Sdarrenr 215145522Sdarrenr ip = fin->fin_ip; 216145522Sdarrenr id = ip->ip_id; 217145522Sdarrenr 21853642Sguido READ_ENTER(&ipf_auth); 21953642Sguido for (i = fr_authstart; i != fr_authend; ) { 22053642Sguido /* 22153642Sguido * index becomes -2 only after an SIOCAUTHW. Check this in 22253642Sguido * case the same packet gets sent again and it hasn't yet been 22353642Sguido * auth'd. 22453642Sguido */ 22580482Sdarrenr fra = fr_auth + i; 22680482Sdarrenr if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 22780482Sdarrenr !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 22853642Sguido /* 22953642Sguido * Avoid feedback loop. 23053642Sguido */ 231145522Sdarrenr if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 23253642Sguido pass = FR_BLOCK; 23380482Sdarrenr /* 23480482Sdarrenr * Create a dummy rule for the stateful checking to 23580482Sdarrenr * use and return. Zero out any values we don't 23680482Sdarrenr * trust from userland! 23780482Sdarrenr */ 23880482Sdarrenr if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 239145522Sdarrenr (fin->fin_flx & FI_FRAG))) { 24080482Sdarrenr KMALLOC(fr, frentry_t *); 24180482Sdarrenr if (fr) { 24280482Sdarrenr bcopy((char *)fra->fra_info.fin_fr, 243145522Sdarrenr (char *)fr, sizeof(*fr)); 24480482Sdarrenr fr->fr_grp = NULL; 24580482Sdarrenr fr->fr_ifa = fin->fin_ifp; 24680482Sdarrenr fr->fr_func = NULL; 24780482Sdarrenr fr->fr_ref = 1; 24880482Sdarrenr fr->fr_flags = pass; 249145522Sdarrenr fr->fr_ifas[1] = NULL; 250145522Sdarrenr fr->fr_ifas[2] = NULL; 251145522Sdarrenr fr->fr_ifas[3] = NULL; 25280482Sdarrenr } 25380482Sdarrenr } else 25480482Sdarrenr fr = fra->fra_info.fin_fr; 25580482Sdarrenr fin->fin_fr = fr; 25653642Sguido RWLOCK_EXIT(&ipf_auth); 257170268Sdarrenr 25853642Sguido WRITE_ENTER(&ipf_auth); 259170268Sdarrenr /* 260170268Sdarrenr * fr_authlist is populated with the rules malloc'd 261170268Sdarrenr * above and only those. 262170268Sdarrenr */ 263145522Sdarrenr if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 26480482Sdarrenr fr->fr_next = fr_authlist; 26580482Sdarrenr fr_authlist = fr; 26680482Sdarrenr } 26753642Sguido fr_authstats.fas_hits++; 26880482Sdarrenr fra->fra_index = -1; 26953642Sguido fr_authused--; 27053642Sguido if (i == fr_authstart) { 27180482Sdarrenr while (fra->fra_index == -1) { 27253642Sguido i++; 27380482Sdarrenr fra++; 274145522Sdarrenr if (i == fr_authsize) { 27553642Sguido i = 0; 27680482Sdarrenr fra = fr_auth; 27780482Sdarrenr } 27853642Sguido fr_authstart = i; 27953642Sguido if (i == fr_authend) 28053642Sguido break; 28153642Sguido } 28253642Sguido if (fr_authstart == fr_authend) { 28353642Sguido fr_authnext = 0; 28453642Sguido fr_authstart = fr_authend = 0; 28553642Sguido } 28653642Sguido } 28753642Sguido RWLOCK_EXIT(&ipf_auth); 288145522Sdarrenr if (passp != NULL) 289145522Sdarrenr *passp = pass; 290145522Sdarrenr ATOMIC_INC64(fr_authstats.fas_hits); 291145522Sdarrenr return fr; 29253642Sguido } 29353642Sguido i++; 294145522Sdarrenr if (i == fr_authsize) 29553642Sguido i = 0; 29653642Sguido } 29753642Sguido fr_authstats.fas_miss++; 29853642Sguido RWLOCK_EXIT(&ipf_auth); 299145522Sdarrenr ATOMIC_INC64(fr_authstats.fas_miss); 300145522Sdarrenr return NULL; 30153642Sguido} 30253642Sguido 30353642Sguido 304170268Sdarrenr/* ------------------------------------------------------------------------ */ 305170268Sdarrenr/* Function: fr_newauth */ 306173931Sdarrenr/* Returns: int - 1 == success, 0 = did not put packet on auth queue */ 307170268Sdarrenr/* Parameters: m(I) - pointer to mb_t with packet in it */ 308170268Sdarrenr/* fin(I) - pointer to packet information */ 309170268Sdarrenr/* */ 310170268Sdarrenr/* Check if we have room in the auth array to hold details for another */ 311170268Sdarrenr/* packet. If we do, store it and wake up any user programs which are */ 312170268Sdarrenr/* waiting to hear about these events. */ 313170268Sdarrenr/* ------------------------------------------------------------------------ */ 314145522Sdarrenrint fr_newauth(m, fin) 31553642Sguidomb_t *m; 31653642Sguidofr_info_t *fin; 31753642Sguido{ 318145522Sdarrenr#if defined(_KERNEL) && defined(MENTAT) 319145522Sdarrenr qpktinfo_t *qpi = fin->fin_qpi; 32060850Sdarrenr#endif 32180482Sdarrenr frauth_t *fra; 322145522Sdarrenr#if !defined(sparc) && !defined(m68k) 323145522Sdarrenr ip_t *ip; 324145522Sdarrenr#endif 32553642Sguido int i; 32653642Sguido 32760850Sdarrenr if (fr_auth_lock) 32860850Sdarrenr return 0; 32960850Sdarrenr 33053642Sguido WRITE_ENTER(&ipf_auth); 331172776Sdarrenr if (((fr_authend + 1) % fr_authsize) == fr_authstart) { 33253642Sguido fr_authstats.fas_nospace++; 33353642Sguido RWLOCK_EXIT(&ipf_auth); 33453642Sguido return 0; 33553642Sguido } 33653642Sguido 33753642Sguido fr_authstats.fas_added++; 33853642Sguido fr_authused++; 33953642Sguido i = fr_authend++; 340145522Sdarrenr if (fr_authend == fr_authsize) 34153642Sguido fr_authend = 0; 342173931Sdarrenr fra = fr_auth + i; 343173931Sdarrenr fra->fra_index = i; 34453642Sguido RWLOCK_EXIT(&ipf_auth); 345145522Sdarrenr 346170268Sdarrenr if (fin->fin_fr != NULL) 347170268Sdarrenr fra->fra_pass = fin->fin_fr->fr_flags; 348170268Sdarrenr else 349170268Sdarrenr fra->fra_pass = 0; 35080482Sdarrenr fra->fra_age = fr_defaultauthage; 35180482Sdarrenr bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 352145522Sdarrenr#if !defined(sparc) && !defined(m68k) 35353642Sguido /* 35453642Sguido * No need to copyback here as we want to undo the changes, not keep 35553642Sguido * them. 35653642Sguido */ 357145522Sdarrenr ip = fin->fin_ip; 358145522Sdarrenr# if defined(MENTAT) && defined(_KERNEL) 359145522Sdarrenr if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 360145522Sdarrenr# endif 36153642Sguido { 36253642Sguido register u_short bo; 36353642Sguido 36453642Sguido bo = ip->ip_len; 36553642Sguido ip->ip_len = htons(bo); 36653642Sguido bo = ip->ip_off; 36753642Sguido ip->ip_off = htons(bo); 36853642Sguido } 369145522Sdarrenr#endif 370145522Sdarrenr#if SOLARIS && defined(_KERNEL) 371172776Sdarrenr COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname); 372145522Sdarrenr m->b_rptr -= qpi->qpi_off; 37353642Sguido fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 374172776Sdarrenr# if !defined(_INET_IP_STACK_H) 375145522Sdarrenr fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ 376172776Sdarrenr# endif 377161356Sguido fra->fra_m = *fin->fin_mp; 378161356Sguido fra->fra_info.fin_mp = &fra->fra_m; 37953642Sguido cv_signal(&ipfauthwait); 380161356Sguido pollwakeup(&iplpollhead[IPL_LOGAUTH], POLLIN|POLLRDNORM); 38153642Sguido#else 38253642Sguido fr_authpkts[i] = m; 383145522Sdarrenr WAKEUP(&fr_authnext,0); 38453642Sguido#endif 38553642Sguido return 1; 38653642Sguido} 38753642Sguido 38853642Sguido 389170268Sdarrenr/* ------------------------------------------------------------------------ */ 390170268Sdarrenr/* Function: fr_auth_ioctl */ 391170268Sdarrenr/* Returns: int - 0 == success, else error */ 392170268Sdarrenr/* Parameters: data(IO) - pointer to ioctl data */ 393170268Sdarrenr/* cmd(I) - ioctl command */ 394170268Sdarrenr/* mode(I) - mode flags associated with open descriptor */ 395170268Sdarrenr/* uid(I) - uid associatd with application making the call */ 396170268Sdarrenr/* ctx(I) - pointer for context */ 397170268Sdarrenr/* */ 398170268Sdarrenr/* This function handles all of the ioctls recognised by the auth component */ 399170268Sdarrenr/* in IPFilter - ie ioctls called on an open fd for /dev/ipauth */ 400170268Sdarrenr/* ------------------------------------------------------------------------ */ 401170268Sdarrenrint fr_auth_ioctl(data, cmd, mode, uid, ctx) 40253642Sguidocaddr_t data; 403145522Sdarrenrioctlcmd_t cmd; 404170268Sdarrenrint mode, uid; 405170268Sdarrenrvoid *ctx; 40653642Sguido{ 407170268Sdarrenr int error = 0, i; 408153876Sguido SPL_INT(s); 40953642Sguido 41053642Sguido switch (cmd) 41153642Sguido { 412170268Sdarrenr case SIOCGENITER : 413170268Sdarrenr { 414170268Sdarrenr ipftoken_t *token; 415170268Sdarrenr ipfgeniter_t iter; 416170268Sdarrenr 417170268Sdarrenr error = fr_inobj(data, &iter, IPFOBJ_GENITER); 418170268Sdarrenr if (error != 0) 419170268Sdarrenr break; 420170268Sdarrenr 421170268Sdarrenr SPL_SCHED(s); 422170268Sdarrenr token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx); 423170268Sdarrenr if (token != NULL) 424170268Sdarrenr error = fr_authgeniter(token, &iter); 425170268Sdarrenr else 426170268Sdarrenr error = ESRCH; 427170268Sdarrenr RWLOCK_EXIT(&ipf_tokens); 428170268Sdarrenr SPL_X(s); 429170268Sdarrenr 430170268Sdarrenr break; 431170268Sdarrenr } 432170268Sdarrenr 433170268Sdarrenr case SIOCADAFR : 434170268Sdarrenr case SIOCRMAFR : 435170268Sdarrenr if (!(mode & FWRITE)) 436170268Sdarrenr error = EPERM; 437170268Sdarrenr else 438170268Sdarrenr error = frrequest(IPL_LOGAUTH, cmd, data, 439170268Sdarrenr fr_active, 1); 440170268Sdarrenr break; 441170268Sdarrenr 44260850Sdarrenr case SIOCSTLCK : 443110915Sdarrenr if (!(mode & FWRITE)) { 444110915Sdarrenr error = EPERM; 445110915Sdarrenr break; 446110915Sdarrenr } 447172776Sdarrenr error = fr_lock(data, &fr_auth_lock); 44860850Sdarrenr break; 449145522Sdarrenr 45053642Sguido case SIOCATHST: 45153642Sguido fr_authstats.fas_faelist = fae_list; 452145522Sdarrenr error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); 45353642Sguido break; 454145522Sdarrenr 455145522Sdarrenr case SIOCIPFFL: 456145522Sdarrenr SPL_NET(s); 457145522Sdarrenr WRITE_ENTER(&ipf_auth); 458145522Sdarrenr i = fr_authflush(); 459145522Sdarrenr RWLOCK_EXIT(&ipf_auth); 460145522Sdarrenr SPL_X(s); 461170268Sdarrenr error = BCOPYOUT((char *)&i, data, sizeof(i)); 462170268Sdarrenr if (error != 0) 463170268Sdarrenr error = EFAULT; 464145522Sdarrenr break; 465145522Sdarrenr 46653642Sguido case SIOCAUTHW: 467170268Sdarrenr error = fr_authwait(data); 46853642Sguido break; 469145522Sdarrenr 47053642Sguido case SIOCAUTHR: 471170268Sdarrenr error = fr_authreply(data); 47253642Sguido break; 473145522Sdarrenr 47453642Sguido default : 47553642Sguido error = EINVAL; 47653642Sguido break; 47753642Sguido } 47853642Sguido return error; 47953642Sguido} 48053642Sguido 48153642Sguido 482170268Sdarrenr/* ------------------------------------------------------------------------ */ 483170268Sdarrenr/* Function: fr_authunload */ 484170268Sdarrenr/* Returns: None */ 485170268Sdarrenr/* Parameters: None */ 486170268Sdarrenr/* */ 487170268Sdarrenr/* Free all network buffer memory used to keep saved packets. */ 488170268Sdarrenr/* ------------------------------------------------------------------------ */ 48953642Sguidovoid fr_authunload() 49053642Sguido{ 49153642Sguido register int i; 49253642Sguido register frauthent_t *fae, **faep; 49380482Sdarrenr frentry_t *fr, **frp; 49453642Sguido mb_t *m; 49553642Sguido 496145522Sdarrenr if (fr_auth != NULL) { 497145522Sdarrenr KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); 498145522Sdarrenr fr_auth = NULL; 499145522Sdarrenr } 500145522Sdarrenr 501145522Sdarrenr if (fr_authpkts != NULL) { 502145522Sdarrenr for (i = 0; i < fr_authsize; i++) { 503145522Sdarrenr m = fr_authpkts[i]; 504145522Sdarrenr if (m != NULL) { 505145522Sdarrenr FREE_MB_T(m); 506145522Sdarrenr fr_authpkts[i] = NULL; 507145522Sdarrenr } 50853642Sguido } 509145522Sdarrenr KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); 510145522Sdarrenr fr_authpkts = NULL; 51153642Sguido } 51253642Sguido 513145522Sdarrenr faep = &fae_list; 514145522Sdarrenr while ((fae = *faep) != NULL) { 51553642Sguido *faep = fae->fae_next; 51653642Sguido KFREE(fae); 51753642Sguido } 51853642Sguido ipauth = NULL; 51980482Sdarrenr 520145522Sdarrenr if (fr_authlist != NULL) { 521145522Sdarrenr for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 52280482Sdarrenr if (fr->fr_ref == 1) { 52380482Sdarrenr *frp = fr->fr_next; 52480482Sdarrenr KFREE(fr); 52580482Sdarrenr } else 52680482Sdarrenr frp = &fr->fr_next; 52780482Sdarrenr } 52880482Sdarrenr } 529145522Sdarrenr 530145522Sdarrenr if (fr_auth_init == 1) { 531145522Sdarrenr# if SOLARIS && defined(_KERNEL) 532145522Sdarrenr cv_destroy(&ipfauthwait); 533145522Sdarrenr# endif 534145522Sdarrenr MUTEX_DESTROY(&ipf_authmx); 535145522Sdarrenr RW_DESTROY(&ipf_auth); 536145522Sdarrenr 537145522Sdarrenr fr_auth_init = 0; 538145522Sdarrenr } 53953642Sguido} 54053642Sguido 54153642Sguido 542170268Sdarrenr/* ------------------------------------------------------------------------ */ 543170268Sdarrenr/* Function: fr_authexpire */ 544170268Sdarrenr/* Returns: None */ 545170268Sdarrenr/* Parameters: None */ 546170268Sdarrenr/* */ 547170268Sdarrenr/* Slowly expire held auth records. Timeouts are set in expectation of */ 548170268Sdarrenr/* this being called twice per second. */ 549170268Sdarrenr/* ------------------------------------------------------------------------ */ 55053642Sguidovoid fr_authexpire() 55153642Sguido{ 552170268Sdarrenr frauthent_t *fae, **faep; 553170268Sdarrenr frentry_t *fr, **frp; 554170268Sdarrenr frauth_t *fra; 55553642Sguido mb_t *m; 556170268Sdarrenr int i; 557153876Sguido SPL_INT(s); 55853642Sguido 55960850Sdarrenr if (fr_auth_lock) 56060850Sdarrenr return; 56160850Sdarrenr 56253642Sguido SPL_NET(s); 56353642Sguido WRITE_ENTER(&ipf_auth); 564145522Sdarrenr for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { 565145522Sdarrenr fra->fra_age--; 566145522Sdarrenr if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { 56753642Sguido FREE_MB_T(m); 56853642Sguido fr_authpkts[i] = NULL; 56953642Sguido fr_auth[i].fra_index = -1; 57053642Sguido fr_authstats.fas_expire++; 57153642Sguido fr_authused--; 57253642Sguido } 57353642Sguido } 57453642Sguido 575170268Sdarrenr /* 576170268Sdarrenr * Expire pre-auth rules 577170268Sdarrenr */ 578145522Sdarrenr for (faep = &fae_list; ((fae = *faep) != NULL); ) { 579145522Sdarrenr fae->fae_age--; 580145522Sdarrenr if (fae->fae_age == 0) { 581170268Sdarrenr fr_authderef(&fae); 58253642Sguido fr_authstats.fas_expire++; 58353642Sguido } else 58453642Sguido faep = &fae->fae_next; 58553642Sguido } 58698004Sdarrenr if (fae_list != NULL) 58798004Sdarrenr ipauth = &fae_list->fae_fr; 58898004Sdarrenr else 58998004Sdarrenr ipauth = NULL; 59080482Sdarrenr 591145522Sdarrenr for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { 59280482Sdarrenr if (fr->fr_ref == 1) { 59380482Sdarrenr *frp = fr->fr_next; 59480482Sdarrenr KFREE(fr); 59580482Sdarrenr } else 59680482Sdarrenr frp = &fr->fr_next; 59780482Sdarrenr } 59853642Sguido RWLOCK_EXIT(&ipf_auth); 59953642Sguido SPL_X(s); 60053642Sguido} 601110915Sdarrenr 602170268Sdarrenr 603170268Sdarrenr/* ------------------------------------------------------------------------ */ 604170268Sdarrenr/* Function: fr_preauthcmd */ 605170268Sdarrenr/* Returns: int - 0 == success, else error */ 606170268Sdarrenr/* Parameters: cmd(I) - ioctl command for rule */ 607170268Sdarrenr/* fr(I) - pointer to ipf rule */ 608170268Sdarrenr/* fptr(I) - pointer to caller's 'fr' */ 609170268Sdarrenr/* */ 610170268Sdarrenr/* ------------------------------------------------------------------------ */ 611110915Sdarrenrint fr_preauthcmd(cmd, fr, frptr) 612145522Sdarrenrioctlcmd_t cmd; 613110915Sdarrenrfrentry_t *fr, **frptr; 614110915Sdarrenr{ 615110915Sdarrenr frauthent_t *fae, **faep; 616110915Sdarrenr int error = 0; 617153876Sguido SPL_INT(s); 618110915Sdarrenr 619145522Sdarrenr if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 620110915Sdarrenr return EIO; 621170268Sdarrenr 622145522Sdarrenr for (faep = &fae_list; ((fae = *faep) != NULL); ) { 623110915Sdarrenr if (&fae->fae_fr == fr) 624110915Sdarrenr break; 625110915Sdarrenr else 626110915Sdarrenr faep = &fae->fae_next; 627145522Sdarrenr } 628145522Sdarrenr 629145522Sdarrenr if (cmd == (ioctlcmd_t)SIOCRMAFR) { 630145522Sdarrenr if (fr == NULL || frptr == NULL) 631110915Sdarrenr error = EINVAL; 632145522Sdarrenr else if (fae == NULL) 633110915Sdarrenr error = ESRCH; 634110915Sdarrenr else { 635145522Sdarrenr SPL_NET(s); 636110915Sdarrenr WRITE_ENTER(&ipf_auth); 637110915Sdarrenr *faep = fae->fae_next; 638145522Sdarrenr if (ipauth == &fae->fae_fr) 639145522Sdarrenr ipauth = fae_list ? &fae_list->fae_fr : NULL; 640145522Sdarrenr RWLOCK_EXIT(&ipf_auth); 641110915Sdarrenr SPL_X(s); 642145522Sdarrenr 643110915Sdarrenr KFREE(fae); 644110915Sdarrenr } 645145522Sdarrenr } else if (fr != NULL && frptr != NULL) { 646110915Sdarrenr KMALLOC(fae, frauthent_t *); 647110915Sdarrenr if (fae != NULL) { 648110915Sdarrenr bcopy((char *)fr, (char *)&fae->fae_fr, 649110915Sdarrenr sizeof(*fr)); 650145522Sdarrenr SPL_NET(s); 651110915Sdarrenr WRITE_ENTER(&ipf_auth); 652110915Sdarrenr fae->fae_age = fr_defaultauthage; 653110915Sdarrenr fae->fae_fr.fr_hits = 0; 654110915Sdarrenr fae->fae_fr.fr_next = *frptr; 655170268Sdarrenr fae->fae_ref = 1; 656110915Sdarrenr *frptr = &fae->fae_fr; 657110915Sdarrenr fae->fae_next = *faep; 658110915Sdarrenr *faep = fae; 659110915Sdarrenr ipauth = &fae_list->fae_fr; 660145522Sdarrenr RWLOCK_EXIT(&ipf_auth); 661110915Sdarrenr SPL_X(s); 662110915Sdarrenr } else 663110915Sdarrenr error = ENOMEM; 664110915Sdarrenr } else 665110915Sdarrenr error = EINVAL; 666110915Sdarrenr return error; 667110915Sdarrenr} 668145522Sdarrenr 669145522Sdarrenr 670170268Sdarrenr/* ------------------------------------------------------------------------ */ 671170268Sdarrenr/* Function: fr_authflush */ 672170268Sdarrenr/* Returns: int - number of auth entries flushed */ 673170268Sdarrenr/* Parameters: None */ 674170268Sdarrenr/* Locks: WRITE(ipf_auth) */ 675170268Sdarrenr/* */ 676170268Sdarrenr/* This function flushs the fr_authpkts array of any packet data with */ 677170268Sdarrenr/* references still there. */ 678170268Sdarrenr/* It is expected that the caller has already acquired the correct locks or */ 679170268Sdarrenr/* set the priority level correctly for this to block out other code paths */ 680170268Sdarrenr/* into these data structures. */ 681170268Sdarrenr/* ------------------------------------------------------------------------ */ 682145522Sdarrenrint fr_authflush() 683145522Sdarrenr{ 684145522Sdarrenr register int i, num_flushed; 685145522Sdarrenr mb_t *m; 686145522Sdarrenr 687145522Sdarrenr if (fr_auth_lock) 688145522Sdarrenr return -1; 689145522Sdarrenr 690145522Sdarrenr num_flushed = 0; 691145522Sdarrenr 692145522Sdarrenr for (i = 0 ; i < fr_authsize; i++) { 693145522Sdarrenr m = fr_authpkts[i]; 694145522Sdarrenr if (m != NULL) { 695145522Sdarrenr FREE_MB_T(m); 696145522Sdarrenr fr_authpkts[i] = NULL; 697145522Sdarrenr fr_auth[i].fra_index = -1; 698145522Sdarrenr /* perhaps add & use a flush counter inst.*/ 699145522Sdarrenr fr_authstats.fas_expire++; 700145522Sdarrenr fr_authused--; 701145522Sdarrenr num_flushed++; 702145522Sdarrenr } 703145522Sdarrenr } 704145522Sdarrenr 705145522Sdarrenr fr_authstart = 0; 706145522Sdarrenr fr_authend = 0; 707145522Sdarrenr fr_authnext = 0; 708145522Sdarrenr 709145522Sdarrenr return num_flushed; 710145522Sdarrenr} 711161356Sguido 712161356Sguido 713170268Sdarrenr/* ------------------------------------------------------------------------ */ 714170268Sdarrenr/* Function: fr_auth_waiting */ 715172776Sdarrenr/* Returns: int - 0 = no pakcets wiating, 1 = packets waiting. */ 716170268Sdarrenr/* Parameters: None */ 717170268Sdarrenr/* */ 718172776Sdarrenr/* Simple truth check to see if there are any packets waiting in the auth */ 719172776Sdarrenr/* queue. */ 720170268Sdarrenr/* ------------------------------------------------------------------------ */ 721161356Sguidoint fr_auth_waiting() 722161356Sguido{ 723172776Sdarrenr return (fr_authused != 0); 724161356Sguido} 725170268Sdarrenr 726170268Sdarrenr 727170268Sdarrenr/* ------------------------------------------------------------------------ */ 728170268Sdarrenr/* Function: fr_authgeniter */ 729170268Sdarrenr/* Returns: int - 0 == success, else error */ 730170268Sdarrenr/* Parameters: token(I) - pointer to ipftoken structure */ 731170268Sdarrenr/* itp(I) - pointer to ipfgeniter structure */ 732170268Sdarrenr/* */ 733170268Sdarrenr/* ------------------------------------------------------------------------ */ 734170268Sdarrenrint fr_authgeniter(token, itp) 735170268Sdarrenripftoken_t *token; 736170268Sdarrenripfgeniter_t *itp; 737170268Sdarrenr{ 738170268Sdarrenr frauthent_t *fae, *next, zero; 739170268Sdarrenr int error; 740170268Sdarrenr 741170268Sdarrenr if (itp->igi_data == NULL) 742170268Sdarrenr return EFAULT; 743170268Sdarrenr 744170268Sdarrenr if (itp->igi_type != IPFGENITER_AUTH) 745170268Sdarrenr return EINVAL; 746170268Sdarrenr 747170268Sdarrenr fae = token->ipt_data; 748170268Sdarrenr READ_ENTER(&ipf_auth); 749170268Sdarrenr if (fae == NULL) { 750170268Sdarrenr next = fae_list; 751170268Sdarrenr } else { 752170268Sdarrenr next = fae->fae_next; 753170268Sdarrenr } 754170268Sdarrenr 755170268Sdarrenr if (next != NULL) { 756170268Sdarrenr /* 757170268Sdarrenr * If we find an auth entry to use, bump its reference count 758170268Sdarrenr * so that it can be used for is_next when we come back. 759170268Sdarrenr */ 760170268Sdarrenr ATOMIC_INC(next->fae_ref); 761170268Sdarrenr if (next->fae_next == NULL) { 762170268Sdarrenr ipf_freetoken(token); 763170268Sdarrenr token = NULL; 764170268Sdarrenr } else { 765170268Sdarrenr token->ipt_data = next; 766170268Sdarrenr } 767170268Sdarrenr } else { 768170268Sdarrenr bzero(&zero, sizeof(zero)); 769170268Sdarrenr next = &zero; 770170268Sdarrenr } 771170268Sdarrenr RWLOCK_EXIT(&ipf_auth); 772170268Sdarrenr 773170268Sdarrenr /* 774170268Sdarrenr * If we had a prior pointer to an auth entry, release it. 775170268Sdarrenr */ 776170268Sdarrenr if (fae != NULL) { 777170268Sdarrenr WRITE_ENTER(&ipf_auth); 778170268Sdarrenr fr_authderef(&fae); 779170268Sdarrenr RWLOCK_EXIT(&ipf_auth); 780170268Sdarrenr } 781170268Sdarrenr 782170268Sdarrenr /* 783170268Sdarrenr * This should arguably be via fr_outobj() so that the auth 784170268Sdarrenr * structure can (if required) be massaged going out. 785170268Sdarrenr */ 786170268Sdarrenr error = COPYOUT(next, itp->igi_data, sizeof(*next)); 787170268Sdarrenr if (error != 0) 788170268Sdarrenr error = EFAULT; 789170268Sdarrenr 790170268Sdarrenr return error; 791170268Sdarrenr} 792170268Sdarrenr 793170268Sdarrenr 794170268Sdarrenr/* ------------------------------------------------------------------------ */ 795170268Sdarrenr/* Function: fr_authderef */ 796170268Sdarrenr/* Returns: None */ 797170268Sdarrenr/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ 798170268Sdarrenr/* Locks: WRITE(ipf_auth) */ 799170268Sdarrenr/* */ 800170268Sdarrenr/* This function unconditionally sets the pointer in the caller to NULL, */ 801170268Sdarrenr/* to make it clear that it should no longer use that pointer, and drops */ 802170268Sdarrenr/* the reference count on the structure by 1. If it reaches 0, free it up. */ 803170268Sdarrenr/* ------------------------------------------------------------------------ */ 804170268Sdarrenrvoid fr_authderef(faep) 805170268Sdarrenrfrauthent_t **faep; 806170268Sdarrenr{ 807170268Sdarrenr frauthent_t *fae; 808170268Sdarrenr 809170268Sdarrenr fae = *faep; 810170268Sdarrenr *faep = NULL; 811170268Sdarrenr 812170268Sdarrenr fae->fae_ref--; 813170268Sdarrenr if (fae->fae_ref == 0) { 814170268Sdarrenr KFREE(fae); 815170268Sdarrenr } 816170268Sdarrenr} 817170268Sdarrenr 818170268Sdarrenr 819170268Sdarrenr/* ------------------------------------------------------------------------ */ 820170268Sdarrenr/* Function: fr_authwait */ 821170268Sdarrenr/* Returns: int - 0 == success, else error */ 822170268Sdarrenr/* Parameters: data(I) - pointer to data from ioctl call */ 823170268Sdarrenr/* */ 824170268Sdarrenr/* This function is called when an application is waiting for a packet to */ 825170268Sdarrenr/* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */ 826170268Sdarrenr/* a packet waiting on the queue then we will return that _one_ immediately.*/ 827170268Sdarrenr/* If there are no packets present in the queue (fr_authpkts) then we go to */ 828170268Sdarrenr/* sleep. */ 829170268Sdarrenr/* ------------------------------------------------------------------------ */ 830170268Sdarrenrint fr_authwait(data) 831170268Sdarrenrchar *data; 832170268Sdarrenr{ 833170268Sdarrenr frauth_t auth, *au = &auth; 834170268Sdarrenr int error, len, i; 835170268Sdarrenr mb_t *m; 836170268Sdarrenr char *t; 837170268Sdarrenr#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 838170268Sdarrenr (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 839170268Sdarrenr SPL_INT(s); 840170268Sdarrenr#endif 841170268Sdarrenr 842170268Sdarrenrfr_authioctlloop: 843170268Sdarrenr error = fr_inobj(data, au, IPFOBJ_FRAUTH); 844170268Sdarrenr if (error != 0) 845170268Sdarrenr return error; 846170268Sdarrenr 847170268Sdarrenr /* 848170268Sdarrenr * XXX Locks are held below over calls to copyout...a better 849170268Sdarrenr * solution needs to be found so this isn't necessary. The situation 850170268Sdarrenr * we are trying to guard against here is an error in the copyout 851170268Sdarrenr * steps should not cause the packet to "disappear" from the queue. 852170268Sdarrenr */ 853170268Sdarrenr READ_ENTER(&ipf_auth); 854170268Sdarrenr 855170268Sdarrenr /* 856170268Sdarrenr * If fr_authnext is not equal to fr_authend it will be because there 857170268Sdarrenr * is a packet waiting to be delt with in the fr_authpkts array. We 858170268Sdarrenr * copy as much of that out to user space as requested. 859170268Sdarrenr */ 860172776Sdarrenr if (fr_authused > 0) { 861172776Sdarrenr while (fr_authpkts[fr_authnext] == NULL) { 862172776Sdarrenr fr_authnext++; 863172776Sdarrenr if (fr_authnext == fr_authsize) 864172776Sdarrenr fr_authnext = 0; 865172776Sdarrenr } 866172776Sdarrenr 867170268Sdarrenr error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH); 868170268Sdarrenr if (error != 0) 869170268Sdarrenr return error; 870170268Sdarrenr 871170268Sdarrenr if (auth.fra_len != 0 && auth.fra_buf != NULL) { 872170268Sdarrenr /* 873170268Sdarrenr * Copy packet contents out to user space if 874170268Sdarrenr * requested. Bail on an error. 875170268Sdarrenr */ 876170268Sdarrenr m = fr_authpkts[fr_authnext]; 877170268Sdarrenr len = MSGDSIZE(m); 878170268Sdarrenr if (len > auth.fra_len) 879170268Sdarrenr len = auth.fra_len; 880170268Sdarrenr auth.fra_len = len; 881170268Sdarrenr 882170268Sdarrenr for (t = auth.fra_buf; m && (len > 0); ) { 883170268Sdarrenr i = MIN(M_LEN(m), len); 884170268Sdarrenr error = copyoutptr(MTOD(m, char *), &t, i); 885170268Sdarrenr len -= i; 886170268Sdarrenr t += i; 887170268Sdarrenr if (error != 0) 888170268Sdarrenr return error; 889170268Sdarrenr m = m->m_next; 890170268Sdarrenr } 891170268Sdarrenr } 892170268Sdarrenr RWLOCK_EXIT(&ipf_auth); 893170268Sdarrenr 894170268Sdarrenr SPL_NET(s); 895170268Sdarrenr WRITE_ENTER(&ipf_auth); 896170268Sdarrenr fr_authnext++; 897170268Sdarrenr if (fr_authnext == fr_authsize) 898170268Sdarrenr fr_authnext = 0; 899170268Sdarrenr RWLOCK_EXIT(&ipf_auth); 900170268Sdarrenr SPL_X(s); 901170268Sdarrenr 902170268Sdarrenr return 0; 903170268Sdarrenr } 904170268Sdarrenr RWLOCK_EXIT(&ipf_auth); 905170268Sdarrenr 906170268Sdarrenr MUTEX_ENTER(&ipf_authmx); 907170268Sdarrenr#ifdef _KERNEL 908170268Sdarrenr# if SOLARIS 909170268Sdarrenr error = 0; 910170268Sdarrenr if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) 911170268Sdarrenr error = EINTR; 912170268Sdarrenr# else /* SOLARIS */ 913170268Sdarrenr# ifdef __hpux 914170268Sdarrenr { 915170268Sdarrenr lock_t *l; 916170268Sdarrenr 917170268Sdarrenr l = get_sleep_lock(&fr_authnext); 918170268Sdarrenr error = sleep(&fr_authnext, PZERO+1); 919170268Sdarrenr spinunlock(l); 920170268Sdarrenr } 921170268Sdarrenr# else 922170268Sdarrenr# ifdef __osf__ 923170268Sdarrenr error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, 924170268Sdarrenr &ipf_authmx, MS_LOCK_SIMPLE); 925170268Sdarrenr# else 926170268Sdarrenr error = SLEEP(&fr_authnext, "fr_authnext"); 927170268Sdarrenr# endif /* __osf__ */ 928170268Sdarrenr# endif /* __hpux */ 929170268Sdarrenr# endif /* SOLARIS */ 930170268Sdarrenr#endif 931170268Sdarrenr MUTEX_EXIT(&ipf_authmx); 932170268Sdarrenr if (error == 0) 933170268Sdarrenr goto fr_authioctlloop; 934170268Sdarrenr return error; 935170268Sdarrenr} 936170268Sdarrenr 937170268Sdarrenr 938170268Sdarrenr/* ------------------------------------------------------------------------ */ 939170268Sdarrenr/* Function: fr_authreply */ 940170268Sdarrenr/* Returns: int - 0 == success, else error */ 941170268Sdarrenr/* Parameters: data(I) - pointer to data from ioctl call */ 942170268Sdarrenr/* */ 943170268Sdarrenr/* This function is called by an application when it wants to return a */ 944170268Sdarrenr/* decision on a packet using the SIOCAUTHR ioctl. This is after it has */ 945170268Sdarrenr/* received information using an SIOCAUTHW. The decision returned in the */ 946170268Sdarrenr/* form of flags, the same as those used in each rule. */ 947170268Sdarrenr/* ------------------------------------------------------------------------ */ 948170268Sdarrenrint fr_authreply(data) 949170268Sdarrenrchar *data; 950170268Sdarrenr{ 951170268Sdarrenr frauth_t auth, *au = &auth, *fra; 952170268Sdarrenr int error, i; 953170268Sdarrenr mb_t *m; 954170268Sdarrenr SPL_INT(s); 955170268Sdarrenr 956170268Sdarrenr error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 957170268Sdarrenr if (error != 0) 958170268Sdarrenr return error; 959170268Sdarrenr 960170268Sdarrenr SPL_NET(s); 961170268Sdarrenr WRITE_ENTER(&ipf_auth); 962170268Sdarrenr 963170268Sdarrenr i = au->fra_index; 964170268Sdarrenr fra = fr_auth + i; 965170268Sdarrenr error = 0; 966170268Sdarrenr 967170268Sdarrenr /* 968170268Sdarrenr * Check the validity of the information being returned with two simple 969170268Sdarrenr * checks. First, the auth index value should be within the size of 970170268Sdarrenr * the array and second the packet id being returned should also match. 971170268Sdarrenr */ 972170268Sdarrenr if ((i < 0) || (i >= fr_authsize) || 973170268Sdarrenr (fra->fra_info.fin_id != au->fra_info.fin_id)) { 974170268Sdarrenr RWLOCK_EXIT(&ipf_auth); 975170268Sdarrenr SPL_X(s); 976170268Sdarrenr return ESRCH; 977170268Sdarrenr } 978170268Sdarrenr 979170268Sdarrenr m = fr_authpkts[i]; 980170268Sdarrenr fra->fra_index = -2; 981170268Sdarrenr fra->fra_pass = au->fra_pass; 982170268Sdarrenr fr_authpkts[i] = NULL; 983170268Sdarrenr 984170268Sdarrenr RWLOCK_EXIT(&ipf_auth); 985170268Sdarrenr 986170268Sdarrenr /* 987170268Sdarrenr * Re-insert the packet back into the packet stream flowing through 988170268Sdarrenr * the kernel in a manner that will mean IPFilter sees the packet 989170268Sdarrenr * again. This is not the same as is done with fastroute, 990170268Sdarrenr * deliberately, as we want to resume the normal packet processing 991170268Sdarrenr * path for it. 992170268Sdarrenr */ 993170268Sdarrenr#ifdef _KERNEL 994170268Sdarrenr if ((m != NULL) && (au->fra_info.fin_out != 0)) { 995170268Sdarrenr error = ipf_inject(&fra->fra_info, m); 996170268Sdarrenr if (error != 0) { 997170268Sdarrenr error = ENOBUFS; 998170268Sdarrenr fr_authstats.fas_sendfail++; 999170268Sdarrenr } else { 1000170268Sdarrenr fr_authstats.fas_sendok++; 1001170268Sdarrenr } 1002170268Sdarrenr } else if (m) { 1003170268Sdarrenr error = ipf_inject(&fra->fra_info, m); 1004170268Sdarrenr if (error != 0) { 1005170268Sdarrenr error = ENOBUFS; 1006170268Sdarrenr fr_authstats.fas_quefail++; 1007170268Sdarrenr } else { 1008170268Sdarrenr fr_authstats.fas_queok++; 1009170268Sdarrenr } 1010170268Sdarrenr } else { 1011170268Sdarrenr error = EINVAL; 1012170268Sdarrenr } 1013170268Sdarrenr 1014170268Sdarrenr /* 1015170268Sdarrenr * If we experience an error which will result in the packet 1016170268Sdarrenr * not being processed, make sure we advance to the next one. 1017170268Sdarrenr */ 1018170268Sdarrenr if (error == ENOBUFS) { 1019173931Sdarrenr WRITE_ENTER(&ipf_auth); 1020170268Sdarrenr fr_authused--; 1021170268Sdarrenr fra->fra_index = -1; 1022170268Sdarrenr fra->fra_pass = 0; 1023170268Sdarrenr if (i == fr_authstart) { 1024170268Sdarrenr while (fra->fra_index == -1) { 1025170268Sdarrenr i++; 1026170268Sdarrenr if (i == fr_authsize) 1027170268Sdarrenr i = 0; 1028170268Sdarrenr fr_authstart = i; 1029170268Sdarrenr if (i == fr_authend) 1030170268Sdarrenr break; 1031170268Sdarrenr } 1032170268Sdarrenr if (fr_authstart == fr_authend) { 1033170268Sdarrenr fr_authnext = 0; 1034170268Sdarrenr fr_authstart = fr_authend = 0; 1035170268Sdarrenr } 1036170268Sdarrenr } 1037173931Sdarrenr RWLOCK_EXIT(&ipf_auth); 1038170268Sdarrenr } 1039170268Sdarrenr#endif /* _KERNEL */ 1040170268Sdarrenr SPL_X(s); 1041170268Sdarrenr 1042170268Sdarrenr return 0; 1043170268Sdarrenr} 1044