1145522Sdarrenr/* $FreeBSD$ */ 2145522Sdarrenr 353642Sguido/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 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> 22255332Scy# ifdef _STDC_C99 23255332Scy# include <stdbool.h> 24255332Scy# endif 2553642Sguido# include <string.h> 26145522Sdarrenr# define _KERNEL 27145522Sdarrenr# ifdef __OpenBSD__ 28145522Sdarrenrstruct file; 29145522Sdarrenr# endif 30145522Sdarrenr# include <sys/uio.h> 31145522Sdarrenr# undef _KERNEL 3253642Sguido#endif 33145522Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 220000) 3453642Sguido# include <sys/filio.h> 3553642Sguido# include <sys/fcntl.h> 3653642Sguido#else 3753642Sguido# include <sys/ioctl.h> 3853642Sguido#endif 39145522Sdarrenr#if !defined(linux) 4053642Sguido# include <sys/protosw.h> 4153642Sguido#endif 4253642Sguido#include <sys/socket.h> 43145522Sdarrenr#if defined(_KERNEL) 4453642Sguido# include <sys/systm.h> 45145522Sdarrenr# if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 4653642Sguido# include <sys/mbuf.h> 4753642Sguido# endif 48145522Sdarrenr#endif 49145522Sdarrenr#if defined(__SVR4) || defined(__svr4__) 5053642Sguido# include <sys/filio.h> 5153642Sguido# include <sys/byteorder.h> 5253642Sguido# ifdef _KERNEL 5353642Sguido# include <sys/dditypes.h> 5453642Sguido# endif 5553642Sguido# include <sys/stream.h> 5653642Sguido# include <sys/kmem.h> 5753642Sguido#endif 58255332Scy#if (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) || \ 59173181Sdarrenr (defined(__FreeBSD_version) &&(__FreeBSD_version >= 400000)) 6053642Sguido# include <sys/queue.h> 6153642Sguido#endif 6253642Sguido#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 6353642Sguido# include <machine/cpu.h> 6453642Sguido#endif 65145522Sdarrenr#if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 66145522Sdarrenr# include <sys/proc.h> 67145522Sdarrenr#endif 68255332Scy#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 400000) && \ 69255332Scy !defined(_KERNEL) 70255332Scy# include <stdbool.h> 71255332Scy#endif 7253642Sguido#include <net/if.h> 7353642Sguido#ifdef sun 7453642Sguido# include <net/af.h> 7553642Sguido#endif 7653642Sguido#include <netinet/in.h> 7753642Sguido#include <netinet/in_systm.h> 7853642Sguido#include <netinet/ip.h> 79249266Sglebius#if !defined(linux) 80249266Sglebius# include <netinet/ip_var.h> 81249266Sglebius#endif 82145522Sdarrenr#if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 8353642Sguido# define KERNEL 84145522Sdarrenr# define _KERNEL 8553642Sguido# define NOT_KERNEL 8653642Sguido#endif 8753642Sguido#ifdef NOT_KERNEL 88145522Sdarrenr# undef _KERNEL 8953642Sguido# undef KERNEL 9053642Sguido#endif 9153642Sguido#include <netinet/tcp.h> 92145522Sdarrenr#if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 9380482Sdarrenrextern struct ifqueue ipintrq; /* ip packet input queue */ 9453642Sguido#else 95145522Sdarrenr# if !defined(__hpux) && !defined(linux) 9653642Sguido# if __FreeBSD_version >= 300000 9753642Sguido# include <net/if_var.h> 98145522Sdarrenr# if __FreeBSD_version >= 500042 99145522Sdarrenr# define IF_QFULL _IF_QFULL 100145522Sdarrenr# define IF_DROP _IF_DROP 101145522Sdarrenr# endif /* __FreeBSD_version >= 500042 */ 10253642Sguido# endif 10353642Sguido# include <netinet/in_var.h> 10453642Sguido# include <netinet/tcp_fsm.h> 10553642Sguido# endif 10653642Sguido#endif 10753642Sguido#include <netinet/udp.h> 10853642Sguido#include <netinet/ip_icmp.h> 10953642Sguido#include "netinet/ip_compat.h" 11053642Sguido#include <netinet/tcpip.h> 11153642Sguido#include "netinet/ip_fil.h" 11253642Sguido#include "netinet/ip_auth.h" 113145522Sdarrenr#if !defined(MENTAT) && !defined(linux) 11453642Sguido# include <net/netisr.h> 11553642Sguido# ifdef __FreeBSD__ 11653642Sguido# include <machine/cpufunc.h> 11753642Sguido# endif 11853642Sguido#endif 11953642Sguido#if (__FreeBSD_version >= 300000) 12053642Sguido# include <sys/malloc.h> 121145522Sdarrenr# if defined(_KERNEL) && !defined(IPFILTER_LKM) 12253642Sguido# include <sys/libkern.h> 12353642Sguido# include <sys/systm.h> 12453642Sguido# endif 12553642Sguido#endif 126145522Sdarrenr/* END OF INCLUDES */ 12753642Sguido 12880482Sdarrenr#if !defined(lint) 12980482Sdarrenrstatic const char rcsid[] = "@(#)$FreeBSD$"; 130172776Sdarrenr/* static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.24 2007/09/09 11:32:04 darrenr Exp $"; */ 13180482Sdarrenr#endif 13253642Sguido 13353642Sguido 134255332Scystatic void ipf_auth_deref __P((frauthent_t **)); 135255332Scystatic void ipf_auth_deref_unlocked __P((ipf_auth_softc_t *, frauthent_t **)); 136255332Scystatic int ipf_auth_geniter __P((ipf_main_softc_t *, ipftoken_t *, 137255332Scy ipfgeniter_t *, ipfobj_t *)); 138255332Scystatic int ipf_auth_reply __P((ipf_main_softc_t *, ipf_auth_softc_t *, char *)); 139255332Scystatic int ipf_auth_wait __P((ipf_main_softc_t *, ipf_auth_softc_t *, char *)); 140255332Scystatic int ipf_auth_flush __P((void *)); 14153642Sguido 142255332Scy 143170268Sdarrenr/* ------------------------------------------------------------------------ */ 144255332Scy/* Function: ipf_auth_main_load */ 145170268Sdarrenr/* Returns: int - 0 == success, else error */ 146170268Sdarrenr/* Parameters: None */ 147170268Sdarrenr/* */ 148255332Scy/* A null-op function that exists as a placeholder so that the flow in */ 149255332Scy/* other functions is obvious. */ 150255332Scy/* ------------------------------------------------------------------------ */ 151255332Scyint 152255332Scyipf_auth_main_load() 153255332Scy{ 154255332Scy return 0; 155255332Scy} 156255332Scy 157255332Scy 158255332Scy/* ------------------------------------------------------------------------ */ 159255332Scy/* Function: ipf_auth_main_unload */ 160255332Scy/* Returns: int - 0 == success, else error */ 161255332Scy/* Parameters: None */ 162255332Scy/* */ 163255332Scy/* A null-op function that exists as a placeholder so that the flow in */ 164255332Scy/* other functions is obvious. */ 165255332Scy/* ------------------------------------------------------------------------ */ 166255332Scyint 167255332Scyipf_auth_main_unload() 168255332Scy{ 169255332Scy return 0; 170255332Scy} 171255332Scy 172255332Scy 173255332Scy/* ------------------------------------------------------------------------ */ 174255332Scy/* Function: ipf_auth_soft_create */ 175255332Scy/* Returns: int - NULL = failure, else success */ 176255332Scy/* Parameters: softc(I) - pointer to soft context data */ 177255332Scy/* */ 178255332Scy/* Create a structre to store all of the run-time data for packet auth in */ 179255332Scy/* and initialise some fields to their defaults. */ 180255332Scy/* ------------------------------------------------------------------------ */ 181255332Scyvoid * 182255332Scyipf_auth_soft_create(softc) 183255332Scy ipf_main_softc_t *softc; 184255332Scy{ 185255332Scy ipf_auth_softc_t *softa; 186255332Scy 187255332Scy KMALLOC(softa, ipf_auth_softc_t *); 188255332Scy if (softa == NULL) 189255332Scy return NULL; 190255332Scy 191255332Scy bzero((char *)softa, sizeof(*softa)); 192255332Scy 193255332Scy softa->ipf_auth_size = FR_NUMAUTH; 194255332Scy softa->ipf_auth_defaultage = 600; 195255332Scy 196255332Scy RWLOCK_INIT(&softa->ipf_authlk, "ipf IP User-Auth rwlock"); 197255332Scy MUTEX_INIT(&softa->ipf_auth_mx, "ipf auth log mutex"); 198255332Scy#if SOLARIS && defined(_KERNEL) 199255332Scy cv_init(&softa->ipf_auth_wait, "ipf auth condvar", CV_DRIVER, NULL); 200255332Scy#endif 201255332Scy 202255332Scy return softa; 203255332Scy} 204255332Scy 205255332Scy/* ------------------------------------------------------------------------ */ 206255332Scy/* Function: ipf_auth_soft_init */ 207255332Scy/* Returns: int - 0 == success, else error */ 208255332Scy/* Parameters: softc(I) - pointer to soft context data */ 209255332Scy/* arg(I) - opaque pointer to auth context data */ 210255332Scy/* */ 211170268Sdarrenr/* Allocate memory and initialise data structures used in handling auth */ 212170268Sdarrenr/* rules. */ 213170268Sdarrenr/* ------------------------------------------------------------------------ */ 214255332Scyint 215255332Scyipf_auth_soft_init(softc, arg) 216255332Scy ipf_main_softc_t *softc; 217255332Scy void *arg; 218145522Sdarrenr{ 219255332Scy ipf_auth_softc_t *softa = arg; 220255332Scy 221255332Scy KMALLOCS(softa->ipf_auth, frauth_t *, 222255332Scy softa->ipf_auth_size * sizeof(*softa->ipf_auth)); 223255332Scy if (softa->ipf_auth == NULL) 224145522Sdarrenr return -1; 225255332Scy bzero((char *)softa->ipf_auth, 226255332Scy softa->ipf_auth_size * sizeof(*softa->ipf_auth)); 227145522Sdarrenr 228255332Scy KMALLOCS(softa->ipf_auth_pkts, mb_t **, 229255332Scy softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts)); 230255332Scy if (softa->ipf_auth_pkts == NULL) 231145522Sdarrenr return -2; 232255332Scy bzero((char *)softa->ipf_auth_pkts, 233255332Scy softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts)); 234145522Sdarrenr 235145522Sdarrenr#if defined(linux) && defined(_KERNEL) 236255332Scy init_waitqueue_head(&softa->ipf_auth_next_linux); 237145522Sdarrenr#endif 238145522Sdarrenr 239255332Scy return 0; 240255332Scy} 241145522Sdarrenr 242255332Scy 243255332Scy/* ------------------------------------------------------------------------ */ 244255332Scy/* Function: ipf_auth_soft_fini */ 245255332Scy/* Returns: int - 0 == success, else error */ 246255332Scy/* Parameters: softc(I) - pointer to soft context data */ 247255332Scy/* arg(I) - opaque pointer to auth context data */ 248255332Scy/* */ 249255332Scy/* Free all network buffer memory used to keep saved packets that have been */ 250255332Scy/* connectedd to the soft soft context structure *but* do not free that: it */ 251255332Scy/* is free'd by _destroy(). */ 252255332Scy/* ------------------------------------------------------------------------ */ 253255332Scyint 254255332Scyipf_auth_soft_fini(softc, arg) 255255332Scy ipf_main_softc_t *softc; 256255332Scy void *arg; 257255332Scy{ 258255332Scy ipf_auth_softc_t *softa = arg; 259255332Scy frauthent_t *fae, **faep; 260255332Scy frentry_t *fr, **frp; 261255332Scy mb_t *m; 262255332Scy int i; 263255332Scy 264255332Scy if (softa->ipf_auth != NULL) { 265255332Scy KFREES(softa->ipf_auth, 266255332Scy softa->ipf_auth_size * sizeof(*softa->ipf_auth)); 267255332Scy softa->ipf_auth = NULL; 268255332Scy } 269255332Scy 270255332Scy if (softa->ipf_auth_pkts != NULL) { 271255332Scy for (i = 0; i < softa->ipf_auth_size; i++) { 272255332Scy m = softa->ipf_auth_pkts[i]; 273255332Scy if (m != NULL) { 274255332Scy FREE_MB_T(m); 275255332Scy softa->ipf_auth_pkts[i] = NULL; 276255332Scy } 277255332Scy } 278255332Scy KFREES(softa->ipf_auth_pkts, 279255332Scy softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts)); 280255332Scy softa->ipf_auth_pkts = NULL; 281255332Scy } 282255332Scy 283255332Scy faep = &softa->ipf_auth_entries; 284255332Scy while ((fae = *faep) != NULL) { 285255332Scy *faep = fae->fae_next; 286255332Scy KFREE(fae); 287255332Scy } 288255332Scy softa->ipf_auth_ip = NULL; 289255332Scy 290255332Scy if (softa->ipf_auth_rules != NULL) { 291255332Scy for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) { 292255332Scy if (fr->fr_ref == 1) { 293255332Scy *frp = fr->fr_next; 294255332Scy MUTEX_DESTROY(&fr->fr_lock); 295255332Scy KFREE(fr); 296255332Scy } else 297255332Scy frp = &fr->fr_next; 298255332Scy } 299255332Scy } 300255332Scy 301145522Sdarrenr return 0; 302145522Sdarrenr} 303145522Sdarrenr 304145522Sdarrenr 305170268Sdarrenr/* ------------------------------------------------------------------------ */ 306255332Scy/* Function: ipf_auth_soft_destroy */ 307255332Scy/* Returns: void */ 308255332Scy/* Parameters: softc(I) - pointer to soft context data */ 309255332Scy/* arg(I) - opaque pointer to auth context data */ 310255332Scy/* */ 311255332Scy/* Undo what was done in _create() - i.e. free the soft context data. */ 312255332Scy/* ------------------------------------------------------------------------ */ 313255332Scyvoid 314255332Scyipf_auth_soft_destroy(softc, arg) 315255332Scy ipf_main_softc_t *softc; 316255332Scy void *arg; 317255332Scy{ 318255332Scy ipf_auth_softc_t *softa = arg; 319255332Scy 320255332Scy# if SOLARIS && defined(_KERNEL) 321255332Scy cv_destroy(&softa->ipf_auth_wait); 322255332Scy# endif 323255332Scy MUTEX_DESTROY(&softa->ipf_auth_mx); 324255332Scy RW_DESTROY(&softa->ipf_authlk); 325255332Scy 326255332Scy KFREE(softa); 327255332Scy} 328255332Scy 329255332Scy 330255332Scy/* ------------------------------------------------------------------------ */ 331255332Scy/* Function: ipf_auth_setlock */ 332255332Scy/* Returns: void */ 333255332Scy/* Paramters: arg(I) - pointer to soft context data */ 334255332Scy/* tmp(I) - value to assign to auth lock */ 335255332Scy/* */ 336255332Scy/* ------------------------------------------------------------------------ */ 337255332Scyvoid 338255332Scyipf_auth_setlock(arg, tmp) 339255332Scy void *arg; 340255332Scy int tmp; 341255332Scy{ 342255332Scy ipf_auth_softc_t *softa = arg; 343255332Scy 344255332Scy softa->ipf_auth_lock = tmp; 345255332Scy} 346255332Scy 347255332Scy 348255332Scy/* ------------------------------------------------------------------------ */ 349255332Scy/* Function: ipf_auth_check */ 350170268Sdarrenr/* Returns: frentry_t* - pointer to ipf rule if match found, else NULL */ 351170268Sdarrenr/* Parameters: fin(I) - pointer to ipftoken structure */ 352170268Sdarrenr/* passp(I) - pointer to ipfgeniter structure */ 353170268Sdarrenr/* */ 354170268Sdarrenr/* Check if a packet has authorization. If the packet is found to match an */ 355170268Sdarrenr/* authorization result and that would result in a feedback loop (i.e. it */ 356170268Sdarrenr/* will end up returning FR_AUTH) then return FR_BLOCK instead. */ 357170268Sdarrenr/* ------------------------------------------------------------------------ */ 358255332Scyfrentry_t * 359255332Scyipf_auth_check(fin, passp) 360255332Scy fr_info_t *fin; 361255332Scy u_32_t *passp; 36253642Sguido{ 363255332Scy ipf_main_softc_t *softc = fin->fin_main_soft; 364255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 36580482Sdarrenr frentry_t *fr; 36680482Sdarrenr frauth_t *fra; 36753642Sguido u_32_t pass; 368145522Sdarrenr u_short id; 369145522Sdarrenr ip_t *ip; 37053642Sguido int i; 37153642Sguido 372255332Scy if (softa->ipf_auth_lock || !softa->ipf_auth_used) 373145522Sdarrenr return NULL; 37460850Sdarrenr 375145522Sdarrenr ip = fin->fin_ip; 376145522Sdarrenr id = ip->ip_id; 377145522Sdarrenr 378255332Scy READ_ENTER(&softa->ipf_authlk); 379255332Scy for (i = softa->ipf_auth_start; i != softa->ipf_auth_end; ) { 38053642Sguido /* 38153642Sguido * index becomes -2 only after an SIOCAUTHW. Check this in 38253642Sguido * case the same packet gets sent again and it hasn't yet been 38353642Sguido * auth'd. 38453642Sguido */ 385255332Scy fra = softa->ipf_auth + i; 38680482Sdarrenr if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 38780482Sdarrenr !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 38853642Sguido /* 38953642Sguido * Avoid feedback loop. 39053642Sguido */ 391255332Scy if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) { 39253642Sguido pass = FR_BLOCK; 393255332Scy fin->fin_reason = FRB_AUTHFEEDBACK; 394255332Scy } 39580482Sdarrenr /* 39680482Sdarrenr * Create a dummy rule for the stateful checking to 39780482Sdarrenr * use and return. Zero out any values we don't 39880482Sdarrenr * trust from userland! 39980482Sdarrenr */ 40080482Sdarrenr if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 401145522Sdarrenr (fin->fin_flx & FI_FRAG))) { 40280482Sdarrenr KMALLOC(fr, frentry_t *); 40380482Sdarrenr if (fr) { 40480482Sdarrenr bcopy((char *)fra->fra_info.fin_fr, 405145522Sdarrenr (char *)fr, sizeof(*fr)); 40680482Sdarrenr fr->fr_grp = NULL; 40780482Sdarrenr fr->fr_ifa = fin->fin_ifp; 40880482Sdarrenr fr->fr_func = NULL; 40980482Sdarrenr fr->fr_ref = 1; 41080482Sdarrenr fr->fr_flags = pass; 411145522Sdarrenr fr->fr_ifas[1] = NULL; 412145522Sdarrenr fr->fr_ifas[2] = NULL; 413145522Sdarrenr fr->fr_ifas[3] = NULL; 414255332Scy MUTEX_INIT(&fr->fr_lock, 415255332Scy "ipf auth rule"); 41680482Sdarrenr } 41780482Sdarrenr } else 41880482Sdarrenr fr = fra->fra_info.fin_fr; 41980482Sdarrenr fin->fin_fr = fr; 420255332Scy fin->fin_flx |= fra->fra_flx; 421255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 422170268Sdarrenr 423255332Scy WRITE_ENTER(&softa->ipf_authlk); 424170268Sdarrenr /* 425255332Scy * ipf_auth_rules is populated with the rules malloc'd 426170268Sdarrenr * above and only those. 427170268Sdarrenr */ 428145522Sdarrenr if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 429255332Scy fr->fr_next = softa->ipf_auth_rules; 430255332Scy softa->ipf_auth_rules = fr; 43180482Sdarrenr } 432255332Scy softa->ipf_auth_stats.fas_hits++; 43380482Sdarrenr fra->fra_index = -1; 434255332Scy softa->ipf_auth_used--; 435255332Scy softa->ipf_auth_replies--; 436255332Scy if (i == softa->ipf_auth_start) { 43780482Sdarrenr while (fra->fra_index == -1) { 43853642Sguido i++; 43980482Sdarrenr fra++; 440255332Scy if (i == softa->ipf_auth_size) { 44153642Sguido i = 0; 442255332Scy fra = softa->ipf_auth; 44380482Sdarrenr } 444255332Scy softa->ipf_auth_start = i; 445255332Scy if (i == softa->ipf_auth_end) 44653642Sguido break; 44753642Sguido } 448255332Scy if (softa->ipf_auth_start == 449255332Scy softa->ipf_auth_end) { 450255332Scy softa->ipf_auth_next = 0; 451255332Scy softa->ipf_auth_start = 0; 452255332Scy softa->ipf_auth_end = 0; 45353642Sguido } 45453642Sguido } 455255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 456145522Sdarrenr if (passp != NULL) 457145522Sdarrenr *passp = pass; 458255332Scy softa->ipf_auth_stats.fas_hits++; 459145522Sdarrenr return fr; 46053642Sguido } 46153642Sguido i++; 462255332Scy if (i == softa->ipf_auth_size) 46353642Sguido i = 0; 46453642Sguido } 465255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 466255332Scy softa->ipf_auth_stats.fas_miss++; 467145522Sdarrenr return NULL; 46853642Sguido} 46953642Sguido 47053642Sguido 471170268Sdarrenr/* ------------------------------------------------------------------------ */ 472255332Scy/* Function: ipf_auth_new */ 473173931Sdarrenr/* Returns: int - 1 == success, 0 = did not put packet on auth queue */ 474170268Sdarrenr/* Parameters: m(I) - pointer to mb_t with packet in it */ 475170268Sdarrenr/* fin(I) - pointer to packet information */ 476170268Sdarrenr/* */ 477170268Sdarrenr/* Check if we have room in the auth array to hold details for another */ 478170268Sdarrenr/* packet. If we do, store it and wake up any user programs which are */ 479170268Sdarrenr/* waiting to hear about these events. */ 480170268Sdarrenr/* ------------------------------------------------------------------------ */ 481255332Scyint 482255332Scyipf_auth_new(m, fin) 483255332Scy mb_t *m; 484255332Scy fr_info_t *fin; 48553642Sguido{ 486255332Scy ipf_main_softc_t *softc = fin->fin_main_soft; 487255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 488145522Sdarrenr#if defined(_KERNEL) && defined(MENTAT) 489145522Sdarrenr qpktinfo_t *qpi = fin->fin_qpi; 49060850Sdarrenr#endif 49180482Sdarrenr frauth_t *fra; 492145522Sdarrenr#if !defined(sparc) && !defined(m68k) 493145522Sdarrenr ip_t *ip; 494145522Sdarrenr#endif 49553642Sguido int i; 49653642Sguido 497255332Scy if (softa->ipf_auth_lock) 49860850Sdarrenr return 0; 49960850Sdarrenr 500255332Scy WRITE_ENTER(&softa->ipf_authlk); 501255332Scy if (((softa->ipf_auth_end + 1) % softa->ipf_auth_size) == 502255332Scy softa->ipf_auth_start) { 503255332Scy softa->ipf_auth_stats.fas_nospace++; 504255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 50553642Sguido return 0; 50653642Sguido } 50753642Sguido 508255332Scy softa->ipf_auth_stats.fas_added++; 509255332Scy softa->ipf_auth_used++; 510255332Scy i = softa->ipf_auth_end++; 511255332Scy if (softa->ipf_auth_end == softa->ipf_auth_size) 512255332Scy softa->ipf_auth_end = 0; 513255332Scy 514255332Scy fra = softa->ipf_auth + i; 515173931Sdarrenr fra->fra_index = i; 516170268Sdarrenr if (fin->fin_fr != NULL) 517170268Sdarrenr fra->fra_pass = fin->fin_fr->fr_flags; 518170268Sdarrenr else 519170268Sdarrenr fra->fra_pass = 0; 520255332Scy fra->fra_age = softa->ipf_auth_defaultage; 52180482Sdarrenr bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 522255332Scy fra->fra_flx = fra->fra_info.fin_flx & (FI_STATE|FI_NATED); 523255332Scy fra->fra_info.fin_flx &= ~(FI_STATE|FI_NATED); 524145522Sdarrenr#if !defined(sparc) && !defined(m68k) 52553642Sguido /* 52653642Sguido * No need to copyback here as we want to undo the changes, not keep 52753642Sguido * them. 52853642Sguido */ 529145522Sdarrenr ip = fin->fin_ip; 530145522Sdarrenr# if defined(MENTAT) && defined(_KERNEL) 531145522Sdarrenr if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 532145522Sdarrenr# endif 53353642Sguido { 53453642Sguido register u_short bo; 53553642Sguido 53653642Sguido bo = ip->ip_len; 53753642Sguido ip->ip_len = htons(bo); 53853642Sguido bo = ip->ip_off; 53953642Sguido ip->ip_off = htons(bo); 54053642Sguido } 541145522Sdarrenr#endif 542145522Sdarrenr#if SOLARIS && defined(_KERNEL) 543172776Sdarrenr COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname); 544145522Sdarrenr m->b_rptr -= qpi->qpi_off; 545145522Sdarrenr fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ 546161356Sguido fra->fra_m = *fin->fin_mp; 547161356Sguido fra->fra_info.fin_mp = &fra->fra_m; 548255332Scy softa->ipf_auth_pkts[i] = *(mblk_t **)fin->fin_mp; 549255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 550255332Scy cv_signal(&softa->ipf_auth_wait); 551255332Scy pollwakeup(&softc->ipf_poll_head[IPL_LOGAUTH], POLLIN|POLLRDNORM); 55253642Sguido#else 553255332Scy softa->ipf_auth_pkts[i] = m; 554255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 555255332Scy WAKEUP(&softa->ipf_auth_next, 0); 55653642Sguido#endif 55753642Sguido return 1; 55853642Sguido} 55953642Sguido 56053642Sguido 561170268Sdarrenr/* ------------------------------------------------------------------------ */ 562255332Scy/* Function: ipf_auth_ioctl */ 563170268Sdarrenr/* Returns: int - 0 == success, else error */ 564170268Sdarrenr/* Parameters: data(IO) - pointer to ioctl data */ 565170268Sdarrenr/* cmd(I) - ioctl command */ 566170268Sdarrenr/* mode(I) - mode flags associated with open descriptor */ 567170268Sdarrenr/* uid(I) - uid associatd with application making the call */ 568170268Sdarrenr/* ctx(I) - pointer for context */ 569170268Sdarrenr/* */ 570170268Sdarrenr/* This function handles all of the ioctls recognised by the auth component */ 571255332Scy/* in IPFilter - ie ioctls called on an open fd for /dev/ipf_auth */ 572170268Sdarrenr/* ------------------------------------------------------------------------ */ 573255332Scyint 574255332Scyipf_auth_ioctl(softc, data, cmd, mode, uid, ctx) 575255332Scy ipf_main_softc_t *softc; 576255332Scy caddr_t data; 577255332Scy ioctlcmd_t cmd; 578255332Scy int mode, uid; 579255332Scy void *ctx; 58053642Sguido{ 581255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 582170268Sdarrenr int error = 0, i; 583153876Sguido SPL_INT(s); 58453642Sguido 58553642Sguido switch (cmd) 58653642Sguido { 587170268Sdarrenr case SIOCGENITER : 588170268Sdarrenr { 589170268Sdarrenr ipftoken_t *token; 590170268Sdarrenr ipfgeniter_t iter; 591255332Scy ipfobj_t obj; 592170268Sdarrenr 593255332Scy error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER); 594170268Sdarrenr if (error != 0) 595170268Sdarrenr break; 596170268Sdarrenr 597170268Sdarrenr SPL_SCHED(s); 598255332Scy token = ipf_token_find(softc, IPFGENITER_AUTH, uid, ctx); 599170268Sdarrenr if (token != NULL) 600255332Scy error = ipf_auth_geniter(softc, token, &iter, &obj); 601255332Scy else { 602255332Scy WRITE_ENTER(&softc->ipf_tokens); 603255332Scy ipf_token_deref(softc, token); 604255332Scy RWLOCK_EXIT(&softc->ipf_tokens); 605255332Scy IPFERROR(10001); 606170268Sdarrenr error = ESRCH; 607255332Scy } 608170268Sdarrenr SPL_X(s); 609170268Sdarrenr 610170268Sdarrenr break; 611170268Sdarrenr } 612170268Sdarrenr 613170268Sdarrenr case SIOCADAFR : 614170268Sdarrenr case SIOCRMAFR : 615255332Scy if (!(mode & FWRITE)) { 616255332Scy IPFERROR(10002); 617170268Sdarrenr error = EPERM; 618255332Scy } else 619255332Scy error = frrequest(softc, IPL_LOGAUTH, cmd, data, 620255332Scy softc->ipf_active, 1); 621170268Sdarrenr break; 622170268Sdarrenr 62360850Sdarrenr case SIOCSTLCK : 624110915Sdarrenr if (!(mode & FWRITE)) { 625255332Scy IPFERROR(10003); 626110915Sdarrenr error = EPERM; 627255332Scy } else { 628255332Scy error = ipf_lock(data, &softa->ipf_auth_lock); 629110915Sdarrenr } 63060850Sdarrenr break; 631145522Sdarrenr 63253642Sguido case SIOCATHST: 633255332Scy softa->ipf_auth_stats.fas_faelist = softa->ipf_auth_entries; 634255332Scy error = ipf_outobj(softc, data, &softa->ipf_auth_stats, 635255332Scy IPFOBJ_AUTHSTAT); 63653642Sguido break; 637145522Sdarrenr 638145522Sdarrenr case SIOCIPFFL: 639145522Sdarrenr SPL_NET(s); 640255332Scy WRITE_ENTER(&softa->ipf_authlk); 641255332Scy i = ipf_auth_flush(softa); 642255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 643145522Sdarrenr SPL_X(s); 644255332Scy error = BCOPYOUT(&i, data, sizeof(i)); 645255332Scy if (error != 0) { 646255332Scy IPFERROR(10004); 647170268Sdarrenr error = EFAULT; 648255332Scy } 649145522Sdarrenr break; 650145522Sdarrenr 65153642Sguido case SIOCAUTHW: 652255332Scy error = ipf_auth_wait(softc, softa, data); 65353642Sguido break; 654145522Sdarrenr 65553642Sguido case SIOCAUTHR: 656255332Scy error = ipf_auth_reply(softc, softa, data); 65753642Sguido break; 658145522Sdarrenr 65953642Sguido default : 660255332Scy IPFERROR(10005); 66153642Sguido error = EINVAL; 66253642Sguido break; 66353642Sguido } 66453642Sguido return error; 66553642Sguido} 66653642Sguido 66753642Sguido 668170268Sdarrenr/* ------------------------------------------------------------------------ */ 669255332Scy/* Function: ipf_auth_expire */ 670170268Sdarrenr/* Returns: None */ 671170268Sdarrenr/* Parameters: None */ 672170268Sdarrenr/* */ 673170268Sdarrenr/* Slowly expire held auth records. Timeouts are set in expectation of */ 674170268Sdarrenr/* this being called twice per second. */ 675170268Sdarrenr/* ------------------------------------------------------------------------ */ 676255332Scyvoid 677255332Scyipf_auth_expire(softc) 678255332Scy ipf_main_softc_t *softc; 67953642Sguido{ 680255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 681170268Sdarrenr frauthent_t *fae, **faep; 682170268Sdarrenr frentry_t *fr, **frp; 683170268Sdarrenr frauth_t *fra; 68453642Sguido mb_t *m; 685170268Sdarrenr int i; 686153876Sguido SPL_INT(s); 68753642Sguido 688255332Scy if (softa->ipf_auth_lock) 68960850Sdarrenr return; 69053642Sguido SPL_NET(s); 691255332Scy WRITE_ENTER(&softa->ipf_authlk); 692255332Scy for (i = 0, fra = softa->ipf_auth; i < softa->ipf_auth_size; 693255332Scy i++, fra++) { 694145522Sdarrenr fra->fra_age--; 695255332Scy if ((fra->fra_age == 0) && 696255332Scy (softa->ipf_auth[i].fra_index != -1)) { 697255332Scy if ((m = softa->ipf_auth_pkts[i]) != NULL) { 698255332Scy FREE_MB_T(m); 699255332Scy softa->ipf_auth_pkts[i] = NULL; 700255332Scy } else if (softa->ipf_auth[i].fra_index == -2) { 701255332Scy softa->ipf_auth_replies--; 702255332Scy } 703255332Scy softa->ipf_auth[i].fra_index = -1; 704255332Scy softa->ipf_auth_stats.fas_expire++; 705255332Scy softa->ipf_auth_used--; 70653642Sguido } 70753642Sguido } 70853642Sguido 709170268Sdarrenr /* 710170268Sdarrenr * Expire pre-auth rules 711170268Sdarrenr */ 712255332Scy for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) { 713145522Sdarrenr fae->fae_age--; 714145522Sdarrenr if (fae->fae_age == 0) { 715255332Scy ipf_auth_deref(&fae); 716255332Scy softa->ipf_auth_stats.fas_expire++; 71753642Sguido } else 71853642Sguido faep = &fae->fae_next; 71953642Sguido } 720255332Scy if (softa->ipf_auth_entries != NULL) 721255332Scy softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr; 72298004Sdarrenr else 723255332Scy softa->ipf_auth_ip = NULL; 72480482Sdarrenr 725255332Scy for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) { 72680482Sdarrenr if (fr->fr_ref == 1) { 72780482Sdarrenr *frp = fr->fr_next; 728255332Scy MUTEX_DESTROY(&fr->fr_lock); 72980482Sdarrenr KFREE(fr); 73080482Sdarrenr } else 73180482Sdarrenr frp = &fr->fr_next; 73280482Sdarrenr } 733255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 73453642Sguido SPL_X(s); 73553642Sguido} 736110915Sdarrenr 737170268Sdarrenr 738170268Sdarrenr/* ------------------------------------------------------------------------ */ 739255332Scy/* Function: ipf_auth_precmd */ 740170268Sdarrenr/* Returns: int - 0 == success, else error */ 741170268Sdarrenr/* Parameters: cmd(I) - ioctl command for rule */ 742170268Sdarrenr/* fr(I) - pointer to ipf rule */ 743170268Sdarrenr/* fptr(I) - pointer to caller's 'fr' */ 744170268Sdarrenr/* */ 745170268Sdarrenr/* ------------------------------------------------------------------------ */ 746255332Scyint 747255332Scyipf_auth_precmd(softc, cmd, fr, frptr) 748255332Scy ipf_main_softc_t *softc; 749255332Scy ioctlcmd_t cmd; 750255332Scy frentry_t *fr, **frptr; 751110915Sdarrenr{ 752255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 753110915Sdarrenr frauthent_t *fae, **faep; 754110915Sdarrenr int error = 0; 755153876Sguido SPL_INT(s); 756110915Sdarrenr 757255332Scy if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) { 758255332Scy IPFERROR(10006); 759110915Sdarrenr return EIO; 760255332Scy } 761170268Sdarrenr 762255332Scy for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) { 763110915Sdarrenr if (&fae->fae_fr == fr) 764110915Sdarrenr break; 765110915Sdarrenr else 766110915Sdarrenr faep = &fae->fae_next; 767145522Sdarrenr } 768145522Sdarrenr 769145522Sdarrenr if (cmd == (ioctlcmd_t)SIOCRMAFR) { 770255332Scy if (fr == NULL || frptr == NULL) { 771255332Scy IPFERROR(10007); 772110915Sdarrenr error = EINVAL; 773255332Scy 774255332Scy } else if (fae == NULL) { 775255332Scy IPFERROR(10008); 776110915Sdarrenr error = ESRCH; 777255332Scy 778255332Scy } else { 779145522Sdarrenr SPL_NET(s); 780255332Scy WRITE_ENTER(&softa->ipf_authlk); 781110915Sdarrenr *faep = fae->fae_next; 782255332Scy if (softa->ipf_auth_ip == &fae->fae_fr) 783255332Scy softa->ipf_auth_ip = softa->ipf_auth_entries ? 784255332Scy &softa->ipf_auth_entries->fae_fr : NULL; 785255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 786110915Sdarrenr SPL_X(s); 787145522Sdarrenr 788110915Sdarrenr KFREE(fae); 789110915Sdarrenr } 790145522Sdarrenr } else if (fr != NULL && frptr != NULL) { 791110915Sdarrenr KMALLOC(fae, frauthent_t *); 792110915Sdarrenr if (fae != NULL) { 793110915Sdarrenr bcopy((char *)fr, (char *)&fae->fae_fr, 794110915Sdarrenr sizeof(*fr)); 795145522Sdarrenr SPL_NET(s); 796255332Scy WRITE_ENTER(&softa->ipf_authlk); 797255332Scy fae->fae_age = softa->ipf_auth_defaultage; 798110915Sdarrenr fae->fae_fr.fr_hits = 0; 799110915Sdarrenr fae->fae_fr.fr_next = *frptr; 800170268Sdarrenr fae->fae_ref = 1; 801110915Sdarrenr *frptr = &fae->fae_fr; 802110915Sdarrenr fae->fae_next = *faep; 803110915Sdarrenr *faep = fae; 804255332Scy softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr; 805255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 806110915Sdarrenr SPL_X(s); 807255332Scy } else { 808255332Scy IPFERROR(10009); 809110915Sdarrenr error = ENOMEM; 810255332Scy } 811255332Scy } else { 812255332Scy IPFERROR(10010); 813110915Sdarrenr error = EINVAL; 814255332Scy } 815110915Sdarrenr return error; 816110915Sdarrenr} 817145522Sdarrenr 818145522Sdarrenr 819170268Sdarrenr/* ------------------------------------------------------------------------ */ 820255332Scy/* Function: ipf_auth_flush */ 821170268Sdarrenr/* Returns: int - number of auth entries flushed */ 822170268Sdarrenr/* Parameters: None */ 823255332Scy/* Locks: WRITE(ipf_authlk) */ 824170268Sdarrenr/* */ 825255332Scy/* This function flushs the ipf_auth_pkts array of any packet data with */ 826170268Sdarrenr/* references still there. */ 827170268Sdarrenr/* It is expected that the caller has already acquired the correct locks or */ 828170268Sdarrenr/* set the priority level correctly for this to block out other code paths */ 829170268Sdarrenr/* into these data structures. */ 830170268Sdarrenr/* ------------------------------------------------------------------------ */ 831255332Scystatic int 832255332Scyipf_auth_flush(arg) 833255332Scy void *arg; 834145522Sdarrenr{ 835255332Scy ipf_auth_softc_t *softa = arg; 836255332Scy int i, num_flushed; 837145522Sdarrenr mb_t *m; 838145522Sdarrenr 839255332Scy if (softa->ipf_auth_lock) 840145522Sdarrenr return -1; 841145522Sdarrenr 842145522Sdarrenr num_flushed = 0; 843145522Sdarrenr 844255332Scy for (i = 0 ; i < softa->ipf_auth_size; i++) { 845255332Scy if (softa->ipf_auth[i].fra_index != -1) { 846255332Scy m = softa->ipf_auth_pkts[i]; 847255332Scy if (m != NULL) { 848255332Scy FREE_MB_T(m); 849255332Scy softa->ipf_auth_pkts[i] = NULL; 850255332Scy } 851255332Scy 852255332Scy softa->ipf_auth[i].fra_index = -1; 853145522Sdarrenr /* perhaps add & use a flush counter inst.*/ 854255332Scy softa->ipf_auth_stats.fas_expire++; 855145522Sdarrenr num_flushed++; 856145522Sdarrenr } 857145522Sdarrenr } 858145522Sdarrenr 859255332Scy softa->ipf_auth_start = 0; 860255332Scy softa->ipf_auth_end = 0; 861255332Scy softa->ipf_auth_next = 0; 862255332Scy softa->ipf_auth_used = 0; 863255332Scy softa->ipf_auth_replies = 0; 864145522Sdarrenr 865145522Sdarrenr return num_flushed; 866145522Sdarrenr} 867161356Sguido 868161356Sguido 869170268Sdarrenr/* ------------------------------------------------------------------------ */ 870255332Scy/* Function: ipf_auth_waiting */ 871255332Scy/* Returns: int - number of packets in the auth queue */ 872170268Sdarrenr/* Parameters: None */ 873170268Sdarrenr/* */ 874172776Sdarrenr/* Simple truth check to see if there are any packets waiting in the auth */ 875172776Sdarrenr/* queue. */ 876170268Sdarrenr/* ------------------------------------------------------------------------ */ 877255332Scyint 878255332Scyipf_auth_waiting(softc) 879255332Scy ipf_main_softc_t *softc; 880161356Sguido{ 881255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 882255332Scy 883255332Scy return (softa->ipf_auth_used != 0); 884161356Sguido} 885170268Sdarrenr 886170268Sdarrenr 887170268Sdarrenr/* ------------------------------------------------------------------------ */ 888255332Scy/* Function: ipf_auth_geniter */ 889170268Sdarrenr/* Returns: int - 0 == success, else error */ 890170268Sdarrenr/* Parameters: token(I) - pointer to ipftoken structure */ 891170268Sdarrenr/* itp(I) - pointer to ipfgeniter structure */ 892255332Scy/* objp(I) - pointer to ipf object destription */ 893170268Sdarrenr/* */ 894255332Scy/* Iterate through the list of entries in the auth queue list. */ 895255332Scy/* objp is used here to get the location of where to do the copy out to. */ 896255332Scy/* Stomping over various fields with new information will not harm anything */ 897170268Sdarrenr/* ------------------------------------------------------------------------ */ 898255332Scystatic int 899255332Scyipf_auth_geniter(softc, token, itp, objp) 900255332Scy ipf_main_softc_t *softc; 901255332Scy ipftoken_t *token; 902255332Scy ipfgeniter_t *itp; 903255332Scy ipfobj_t *objp; 904170268Sdarrenr{ 905255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 906170268Sdarrenr frauthent_t *fae, *next, zero; 907170268Sdarrenr int error; 908170268Sdarrenr 909255332Scy if (itp->igi_data == NULL) { 910255332Scy IPFERROR(10011); 911170268Sdarrenr return EFAULT; 912255332Scy } 913170268Sdarrenr 914255332Scy if (itp->igi_type != IPFGENITER_AUTH) { 915255332Scy IPFERROR(10012); 916170268Sdarrenr return EINVAL; 917255332Scy } 918170268Sdarrenr 919255332Scy objp->ipfo_type = IPFOBJ_FRAUTH; 920255332Scy objp->ipfo_ptr = itp->igi_data; 921255332Scy objp->ipfo_size = sizeof(frauth_t); 922255332Scy 923255332Scy READ_ENTER(&softa->ipf_authlk); 924255332Scy 925170268Sdarrenr fae = token->ipt_data; 926170268Sdarrenr if (fae == NULL) { 927255332Scy next = softa->ipf_auth_entries; 928170268Sdarrenr } else { 929170268Sdarrenr next = fae->fae_next; 930170268Sdarrenr } 931170268Sdarrenr 932255332Scy /* 933255332Scy * If we found an auth entry to use, bump its reference count 934255332Scy * so that it can be used for is_next when we come back. 935255332Scy */ 936170268Sdarrenr if (next != NULL) { 937170268Sdarrenr ATOMIC_INC(next->fae_ref); 938255332Scy token->ipt_data = next; 939170268Sdarrenr } else { 940170268Sdarrenr bzero(&zero, sizeof(zero)); 941170268Sdarrenr next = &zero; 942255332Scy token->ipt_data = NULL; 943170268Sdarrenr } 944170268Sdarrenr 945255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 946170268Sdarrenr 947255332Scy error = ipf_outobjk(softc, objp, next); 948255332Scy if (fae != NULL) 949255332Scy ipf_auth_deref_unlocked(softa, &fae); 950170268Sdarrenr 951255332Scy if (next->fae_next == NULL) 952255332Scy ipf_token_mark_complete(token); 953170268Sdarrenr return error; 954170268Sdarrenr} 955170268Sdarrenr 956170268Sdarrenr 957170268Sdarrenr/* ------------------------------------------------------------------------ */ 958255332Scy/* Function: ipf_auth_deref_unlocked */ 959170268Sdarrenr/* Returns: None */ 960170268Sdarrenr/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ 961170268Sdarrenr/* */ 962255332Scy/* Wrapper for ipf_auth_deref for when a write lock on ipf_authlk is not */ 963255332Scy/* held. */ 964255332Scy/* ------------------------------------------------------------------------ */ 965255332Scystatic void 966255332Scyipf_auth_deref_unlocked(softa, faep) 967255332Scy ipf_auth_softc_t *softa; 968255332Scy frauthent_t **faep; 969255332Scy{ 970255332Scy WRITE_ENTER(&softa->ipf_authlk); 971255332Scy ipf_auth_deref(faep); 972255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 973255332Scy} 974255332Scy 975255332Scy 976255332Scy/* ------------------------------------------------------------------------ */ 977255332Scy/* Function: ipf_auth_deref */ 978255332Scy/* Returns: None */ 979255332Scy/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ 980255332Scy/* Locks: WRITE(ipf_authlk) */ 981255332Scy/* */ 982170268Sdarrenr/* This function unconditionally sets the pointer in the caller to NULL, */ 983170268Sdarrenr/* to make it clear that it should no longer use that pointer, and drops */ 984170268Sdarrenr/* the reference count on the structure by 1. If it reaches 0, free it up. */ 985170268Sdarrenr/* ------------------------------------------------------------------------ */ 986255332Scystatic void 987255332Scyipf_auth_deref(faep) 988255332Scy frauthent_t **faep; 989170268Sdarrenr{ 990170268Sdarrenr frauthent_t *fae; 991170268Sdarrenr 992170268Sdarrenr fae = *faep; 993170268Sdarrenr *faep = NULL; 994170268Sdarrenr 995170268Sdarrenr fae->fae_ref--; 996170268Sdarrenr if (fae->fae_ref == 0) { 997170268Sdarrenr KFREE(fae); 998170268Sdarrenr } 999170268Sdarrenr} 1000170268Sdarrenr 1001170268Sdarrenr 1002170268Sdarrenr/* ------------------------------------------------------------------------ */ 1003255332Scy/* Function: ipf_auth_wait_pkt */ 1004170268Sdarrenr/* Returns: int - 0 == success, else error */ 1005170268Sdarrenr/* Parameters: data(I) - pointer to data from ioctl call */ 1006170268Sdarrenr/* */ 1007170268Sdarrenr/* This function is called when an application is waiting for a packet to */ 1008170268Sdarrenr/* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */ 1009170268Sdarrenr/* a packet waiting on the queue then we will return that _one_ immediately.*/ 1010255332Scy/* If there are no packets present in the queue (ipf_auth_pkts) then we go */ 1011255332Scy/* to sleep. */ 1012170268Sdarrenr/* ------------------------------------------------------------------------ */ 1013255332Scystatic int 1014255332Scyipf_auth_wait(softc, softa, data) 1015255332Scy ipf_main_softc_t *softc; 1016255332Scy ipf_auth_softc_t *softa; 1017255332Scy char *data; 1018170268Sdarrenr{ 1019170268Sdarrenr frauth_t auth, *au = &auth; 1020170268Sdarrenr int error, len, i; 1021170268Sdarrenr mb_t *m; 1022170268Sdarrenr char *t; 1023170268Sdarrenr SPL_INT(s); 1024170268Sdarrenr 1025255332Scyipf_auth_ioctlloop: 1026255332Scy error = ipf_inobj(softc, data, NULL, au, IPFOBJ_FRAUTH); 1027170268Sdarrenr if (error != 0) 1028170268Sdarrenr return error; 1029170268Sdarrenr 1030170268Sdarrenr /* 1031170268Sdarrenr * XXX Locks are held below over calls to copyout...a better 1032170268Sdarrenr * solution needs to be found so this isn't necessary. The situation 1033170268Sdarrenr * we are trying to guard against here is an error in the copyout 1034170268Sdarrenr * steps should not cause the packet to "disappear" from the queue. 1035170268Sdarrenr */ 1036255332Scy SPL_NET(s); 1037255332Scy READ_ENTER(&softa->ipf_authlk); 1038170268Sdarrenr 1039170268Sdarrenr /* 1040255332Scy * If ipf_auth_next is not equal to ipf_auth_end it will be because 1041255332Scy * there is a packet waiting to be delt with in the ipf_auth_pkts 1042255332Scy * array. We copy as much of that out to user space as requested. 1043170268Sdarrenr */ 1044255332Scy if (softa->ipf_auth_used > 0) { 1045255332Scy while (softa->ipf_auth_pkts[softa->ipf_auth_next] == NULL) { 1046255332Scy softa->ipf_auth_next++; 1047255332Scy if (softa->ipf_auth_next == softa->ipf_auth_size) 1048255332Scy softa->ipf_auth_next = 0; 1049172776Sdarrenr } 1050172776Sdarrenr 1051255332Scy error = ipf_outobj(softc, data, 1052255332Scy &softa->ipf_auth[softa->ipf_auth_next], 1053255332Scy IPFOBJ_FRAUTH); 1054255332Scy if (error != 0) { 1055255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1056255332Scy SPL_X(s); 1057170268Sdarrenr return error; 1058255332Scy } 1059170268Sdarrenr 1060170268Sdarrenr if (auth.fra_len != 0 && auth.fra_buf != NULL) { 1061170268Sdarrenr /* 1062170268Sdarrenr * Copy packet contents out to user space if 1063170268Sdarrenr * requested. Bail on an error. 1064170268Sdarrenr */ 1065255332Scy m = softa->ipf_auth_pkts[softa->ipf_auth_next]; 1066170268Sdarrenr len = MSGDSIZE(m); 1067170268Sdarrenr if (len > auth.fra_len) 1068170268Sdarrenr len = auth.fra_len; 1069170268Sdarrenr auth.fra_len = len; 1070170268Sdarrenr 1071170268Sdarrenr for (t = auth.fra_buf; m && (len > 0); ) { 1072170268Sdarrenr i = MIN(M_LEN(m), len); 1073255332Scy error = copyoutptr(softc, MTOD(m, char *), 1074255332Scy &t, i); 1075170268Sdarrenr len -= i; 1076170268Sdarrenr t += i; 1077255332Scy if (error != 0) { 1078255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1079255332Scy SPL_X(s); 1080170268Sdarrenr return error; 1081255332Scy } 1082170268Sdarrenr m = m->m_next; 1083170268Sdarrenr } 1084170268Sdarrenr } 1085255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1086170268Sdarrenr 1087170268Sdarrenr SPL_NET(s); 1088255332Scy WRITE_ENTER(&softa->ipf_authlk); 1089255332Scy softa->ipf_auth_next++; 1090255332Scy if (softa->ipf_auth_next == softa->ipf_auth_size) 1091255332Scy softa->ipf_auth_next = 0; 1092255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1093170268Sdarrenr SPL_X(s); 1094170268Sdarrenr 1095170268Sdarrenr return 0; 1096170268Sdarrenr } 1097255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1098255332Scy SPL_X(s); 1099170268Sdarrenr 1100255332Scy MUTEX_ENTER(&softa->ipf_auth_mx); 1101170268Sdarrenr#ifdef _KERNEL 1102170268Sdarrenr# if SOLARIS 1103170268Sdarrenr error = 0; 1104255332Scy if (!cv_wait_sig(&softa->ipf_auth_wait, &softa->ipf_auth_mx.ipf_lk)) { 1105255332Scy IPFERROR(10014); 1106170268Sdarrenr error = EINTR; 1107255332Scy } 1108170268Sdarrenr# else /* SOLARIS */ 1109170268Sdarrenr# ifdef __hpux 1110170268Sdarrenr { 1111170268Sdarrenr lock_t *l; 1112170268Sdarrenr 1113255332Scy l = get_sleep_lock(&softa->ipf_auth_next); 1114255332Scy error = sleep(&softa->ipf_auth_next, PZERO+1); 1115170268Sdarrenr spinunlock(l); 1116170268Sdarrenr } 1117170268Sdarrenr# else 1118170268Sdarrenr# ifdef __osf__ 1119255332Scy error = mpsleep(&softa->ipf_auth_next, PSUSP|PCATCH, "ipf_auth_next", 1120255332Scy 0, &softa->ipf_auth_mx, MS_LOCK_SIMPLE); 1121170268Sdarrenr# else 1122255332Scy error = SLEEP(&softa->ipf_auth_next, "ipf_auth_next"); 1123170268Sdarrenr# endif /* __osf__ */ 1124170268Sdarrenr# endif /* __hpux */ 1125170268Sdarrenr# endif /* SOLARIS */ 1126170268Sdarrenr#endif 1127255332Scy MUTEX_EXIT(&softa->ipf_auth_mx); 1128170268Sdarrenr if (error == 0) 1129255332Scy goto ipf_auth_ioctlloop; 1130170268Sdarrenr return error; 1131170268Sdarrenr} 1132170268Sdarrenr 1133170268Sdarrenr 1134170268Sdarrenr/* ------------------------------------------------------------------------ */ 1135255332Scy/* Function: ipf_auth_reply */ 1136170268Sdarrenr/* Returns: int - 0 == success, else error */ 1137170268Sdarrenr/* Parameters: data(I) - pointer to data from ioctl call */ 1138170268Sdarrenr/* */ 1139170268Sdarrenr/* This function is called by an application when it wants to return a */ 1140170268Sdarrenr/* decision on a packet using the SIOCAUTHR ioctl. This is after it has */ 1141170268Sdarrenr/* received information using an SIOCAUTHW. The decision returned in the */ 1142170268Sdarrenr/* form of flags, the same as those used in each rule. */ 1143170268Sdarrenr/* ------------------------------------------------------------------------ */ 1144255332Scystatic int 1145255332Scyipf_auth_reply(softc, softa, data) 1146255332Scy ipf_main_softc_t *softc; 1147255332Scy ipf_auth_softc_t *softa; 1148255332Scy char *data; 1149170268Sdarrenr{ 1150170268Sdarrenr frauth_t auth, *au = &auth, *fra; 1151255332Scy fr_info_t fin; 1152170268Sdarrenr int error, i; 1153170268Sdarrenr mb_t *m; 1154170268Sdarrenr SPL_INT(s); 1155170268Sdarrenr 1156255332Scy error = ipf_inobj(softc, data, NULL, &auth, IPFOBJ_FRAUTH); 1157170268Sdarrenr if (error != 0) 1158170268Sdarrenr return error; 1159170268Sdarrenr 1160170268Sdarrenr SPL_NET(s); 1161255332Scy WRITE_ENTER(&softa->ipf_authlk); 1162170268Sdarrenr 1163170268Sdarrenr i = au->fra_index; 1164255332Scy fra = softa->ipf_auth + i; 1165170268Sdarrenr error = 0; 1166170268Sdarrenr 1167170268Sdarrenr /* 1168170268Sdarrenr * Check the validity of the information being returned with two simple 1169170268Sdarrenr * checks. First, the auth index value should be within the size of 1170170268Sdarrenr * the array and second the packet id being returned should also match. 1171170268Sdarrenr */ 1172255332Scy if ((i < 0) || (i >= softa->ipf_auth_size)) { 1173255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1174170268Sdarrenr SPL_X(s); 1175255332Scy IPFERROR(10015); 1176170268Sdarrenr return ESRCH; 1177170268Sdarrenr } 1178255332Scy if (fra->fra_info.fin_id != au->fra_info.fin_id) { 1179255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1180255332Scy SPL_X(s); 1181255332Scy IPFERROR(10019); 1182255332Scy return ESRCH; 1183255332Scy } 1184170268Sdarrenr 1185255332Scy m = softa->ipf_auth_pkts[i]; 1186170268Sdarrenr fra->fra_index = -2; 1187170268Sdarrenr fra->fra_pass = au->fra_pass; 1188255332Scy softa->ipf_auth_pkts[i] = NULL; 1189255332Scy softa->ipf_auth_replies++; 1190255332Scy bcopy(&fra->fra_info, &fin, sizeof(fin)); 1191170268Sdarrenr 1192255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1193170268Sdarrenr 1194170268Sdarrenr /* 1195170268Sdarrenr * Re-insert the packet back into the packet stream flowing through 1196170268Sdarrenr * the kernel in a manner that will mean IPFilter sees the packet 1197170268Sdarrenr * again. This is not the same as is done with fastroute, 1198170268Sdarrenr * deliberately, as we want to resume the normal packet processing 1199170268Sdarrenr * path for it. 1200170268Sdarrenr */ 1201170268Sdarrenr#ifdef _KERNEL 1202170268Sdarrenr if ((m != NULL) && (au->fra_info.fin_out != 0)) { 1203255332Scy error = ipf_inject(&fin, m); 1204170268Sdarrenr if (error != 0) { 1205255332Scy IPFERROR(10016); 1206170268Sdarrenr error = ENOBUFS; 1207255332Scy softa->ipf_auth_stats.fas_sendfail++; 1208170268Sdarrenr } else { 1209255332Scy softa->ipf_auth_stats.fas_sendok++; 1210170268Sdarrenr } 1211170268Sdarrenr } else if (m) { 1212255332Scy error = ipf_inject(&fin, m); 1213170268Sdarrenr if (error != 0) { 1214255332Scy IPFERROR(10017); 1215170268Sdarrenr error = ENOBUFS; 1216255332Scy softa->ipf_auth_stats.fas_quefail++; 1217170268Sdarrenr } else { 1218255332Scy softa->ipf_auth_stats.fas_queok++; 1219170268Sdarrenr } 1220170268Sdarrenr } else { 1221255332Scy IPFERROR(10018); 1222170268Sdarrenr error = EINVAL; 1223170268Sdarrenr } 1224170268Sdarrenr 1225170268Sdarrenr /* 1226170268Sdarrenr * If we experience an error which will result in the packet 1227170268Sdarrenr * not being processed, make sure we advance to the next one. 1228170268Sdarrenr */ 1229170268Sdarrenr if (error == ENOBUFS) { 1230255332Scy WRITE_ENTER(&softa->ipf_authlk); 1231255332Scy softa->ipf_auth_used--; 1232170268Sdarrenr fra->fra_index = -1; 1233170268Sdarrenr fra->fra_pass = 0; 1234255332Scy if (i == softa->ipf_auth_start) { 1235170268Sdarrenr while (fra->fra_index == -1) { 1236170268Sdarrenr i++; 1237255332Scy if (i == softa->ipf_auth_size) 1238170268Sdarrenr i = 0; 1239255332Scy softa->ipf_auth_start = i; 1240255332Scy if (i == softa->ipf_auth_end) 1241170268Sdarrenr break; 1242170268Sdarrenr } 1243255332Scy if (softa->ipf_auth_start == softa->ipf_auth_end) { 1244255332Scy softa->ipf_auth_next = 0; 1245255332Scy softa->ipf_auth_start = 0; 1246255332Scy softa->ipf_auth_end = 0; 1247170268Sdarrenr } 1248170268Sdarrenr } 1249255332Scy RWLOCK_EXIT(&softa->ipf_authlk); 1250170268Sdarrenr } 1251170268Sdarrenr#endif /* _KERNEL */ 1252170268Sdarrenr SPL_X(s); 1253170268Sdarrenr 1254170268Sdarrenr return 0; 1255170268Sdarrenr} 1256255332Scy 1257255332Scy 1258255332Scyu_32_t 1259255332Scyipf_auth_pre_scanlist(softc, fin, pass) 1260255332Scy ipf_main_softc_t *softc; 1261255332Scy fr_info_t *fin; 1262255332Scy u_32_t pass; 1263255332Scy{ 1264255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 1265255332Scy 1266255332Scy if (softa->ipf_auth_ip != NULL) 1267255332Scy return ipf_scanlist(fin, softc->ipf_pass); 1268255332Scy 1269255332Scy return pass; 1270255332Scy} 1271255332Scy 1272255332Scy 1273255332Scyfrentry_t ** 1274255332Scyipf_auth_rulehead(softc) 1275255332Scy ipf_main_softc_t *softc; 1276255332Scy{ 1277255332Scy ipf_auth_softc_t *softa = softc->ipf_auth_soft; 1278255332Scy 1279255332Scy return &softa->ipf_auth_ip; 1280255332Scy} 1281