17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing. 5f4b3ec61Sdh * 6786c7074Sjojemann * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7381a2a9aSdr * Use is subject to license terms. 8381a2a9aSdr */ 9381a2a9aSdr 107c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL) 117c478bd9Sstevel@tonic-gate # undef KERNEL 127c478bd9Sstevel@tonic-gate # undef _KERNEL 137c478bd9Sstevel@tonic-gate # define KERNEL 1 147c478bd9Sstevel@tonic-gate # define _KERNEL 1 157c478bd9Sstevel@tonic-gate #endif 167c478bd9Sstevel@tonic-gate #include <sys/errno.h> 177c478bd9Sstevel@tonic-gate #include <sys/types.h> 187c478bd9Sstevel@tonic-gate #include <sys/param.h> 197c478bd9Sstevel@tonic-gate #include <sys/time.h> 207c478bd9Sstevel@tonic-gate #include <sys/file.h> 217c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) 227c478bd9Sstevel@tonic-gate # include <stdio.h> 237c478bd9Sstevel@tonic-gate # include <stdlib.h> 247c478bd9Sstevel@tonic-gate # include <string.h> 257c478bd9Sstevel@tonic-gate # define _KERNEL 267c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__ 277c478bd9Sstevel@tonic-gate struct file; 287c478bd9Sstevel@tonic-gate # endif 297c478bd9Sstevel@tonic-gate # include <sys/uio.h> 307c478bd9Sstevel@tonic-gate # undef _KERNEL 317c478bd9Sstevel@tonic-gate #endif 327c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 337c478bd9Sstevel@tonic-gate # include <sys/filio.h> 347c478bd9Sstevel@tonic-gate # include <sys/fcntl.h> 357c478bd9Sstevel@tonic-gate #else 367c478bd9Sstevel@tonic-gate # include <sys/ioctl.h> 377c478bd9Sstevel@tonic-gate #endif 38ab25eeb5Syz #if !defined(linux) 39ab25eeb5Syz # include <sys/protosw.h> 40ab25eeb5Syz #endif 417c478bd9Sstevel@tonic-gate #include <sys/socket.h> 427c478bd9Sstevel@tonic-gate #if defined(_KERNEL) 437c478bd9Sstevel@tonic-gate # include <sys/systm.h> 44ab25eeb5Syz # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) 457c478bd9Sstevel@tonic-gate # include <sys/mbuf.h> 467c478bd9Sstevel@tonic-gate # endif 477c478bd9Sstevel@tonic-gate #endif 487c478bd9Sstevel@tonic-gate #if defined(__SVR4) || defined(__svr4__) 497c478bd9Sstevel@tonic-gate # include <sys/filio.h> 507c478bd9Sstevel@tonic-gate # include <sys/byteorder.h> 517c478bd9Sstevel@tonic-gate # ifdef _KERNEL 527c478bd9Sstevel@tonic-gate # include <sys/dditypes.h> 537c478bd9Sstevel@tonic-gate # endif 547c478bd9Sstevel@tonic-gate # include <sys/stream.h> 557c478bd9Sstevel@tonic-gate # include <sys/kmem.h> 56381a2a9aSdr # include <sys/neti.h> 577c478bd9Sstevel@tonic-gate #endif 587c478bd9Sstevel@tonic-gate #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) 597c478bd9Sstevel@tonic-gate # include <sys/queue.h> 607c478bd9Sstevel@tonic-gate #endif 617c478bd9Sstevel@tonic-gate #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) 627c478bd9Sstevel@tonic-gate # include <machine/cpu.h> 637c478bd9Sstevel@tonic-gate #endif 647c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) 657c478bd9Sstevel@tonic-gate # include <sys/proc.h> 667c478bd9Sstevel@tonic-gate #endif 677c478bd9Sstevel@tonic-gate #include <net/if.h> 687c478bd9Sstevel@tonic-gate #ifdef sun 697c478bd9Sstevel@tonic-gate # include <net/af.h> 707c478bd9Sstevel@tonic-gate #endif 717c478bd9Sstevel@tonic-gate #include <net/route.h> 727c478bd9Sstevel@tonic-gate #include <netinet/in.h> 737c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 747c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 75ab25eeb5Syz #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) 767c478bd9Sstevel@tonic-gate # define KERNEL 777c478bd9Sstevel@tonic-gate # define _KERNEL 787c478bd9Sstevel@tonic-gate # define NOT_KERNEL 797c478bd9Sstevel@tonic-gate #endif 80ab25eeb5Syz #if !defined(linux) 81ab25eeb5Syz # include <netinet/ip_var.h> 82ab25eeb5Syz #endif 837c478bd9Sstevel@tonic-gate #ifdef NOT_KERNEL 847c478bd9Sstevel@tonic-gate # undef _KERNEL 857c478bd9Sstevel@tonic-gate # undef KERNEL 867c478bd9Sstevel@tonic-gate #endif 877c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 88ab25eeb5Syz #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ 897c478bd9Sstevel@tonic-gate extern struct ifqueue ipintrq; /* ip packet input queue */ 907c478bd9Sstevel@tonic-gate #else 91ab25eeb5Syz # if !defined(__hpux) && !defined(linux) 927c478bd9Sstevel@tonic-gate # if __FreeBSD_version >= 300000 937c478bd9Sstevel@tonic-gate # include <net/if_var.h> 947c478bd9Sstevel@tonic-gate # if __FreeBSD_version >= 500042 957c478bd9Sstevel@tonic-gate # define IF_QFULL _IF_QFULL 967c478bd9Sstevel@tonic-gate # define IF_DROP _IF_DROP 977c478bd9Sstevel@tonic-gate # endif /* __FreeBSD_version >= 500042 */ 987c478bd9Sstevel@tonic-gate # endif 997c478bd9Sstevel@tonic-gate # include <netinet/in_var.h> 1007c478bd9Sstevel@tonic-gate # include <netinet/tcp_fsm.h> 1017c478bd9Sstevel@tonic-gate # endif 1027c478bd9Sstevel@tonic-gate #endif 1037c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 1047c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h> 1057c478bd9Sstevel@tonic-gate #include "netinet/ip_compat.h" 106ab25eeb5Syz #include <netinet/tcpip.h> 107f4b3ec61Sdh #include "netinet/ipf_stack.h" 1087c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h" 1097c478bd9Sstevel@tonic-gate #include "netinet/ip_auth.h" 110ab25eeb5Syz #if !defined(MENTAT) && !defined(linux) 1117c478bd9Sstevel@tonic-gate # include <net/netisr.h> 1127c478bd9Sstevel@tonic-gate # ifdef __FreeBSD__ 1137c478bd9Sstevel@tonic-gate # include <machine/cpufunc.h> 1147c478bd9Sstevel@tonic-gate # endif 1157c478bd9Sstevel@tonic-gate #endif 1167c478bd9Sstevel@tonic-gate #if (__FreeBSD_version >= 300000) 1177c478bd9Sstevel@tonic-gate # include <sys/malloc.h> 1187c478bd9Sstevel@tonic-gate # if defined(_KERNEL) && !defined(IPFILTER_LKM) 1197c478bd9Sstevel@tonic-gate # include <sys/libkern.h> 1207c478bd9Sstevel@tonic-gate # include <sys/systm.h> 1217c478bd9Sstevel@tonic-gate # endif 1227c478bd9Sstevel@tonic-gate #endif 123ab25eeb5Syz /* END OF INCLUDES */ 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #if !defined(lint) 126ab25eeb5Syz static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.5 2005/06/12 07:18:14 darrenr Exp $"; 1277c478bd9Sstevel@tonic-gate #endif 1287c478bd9Sstevel@tonic-gate 129f4b3ec61Sdh void fr_authderef __P((frauthent_t **)); 130f4b3ec61Sdh int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate 133f4b3ec61Sdh int fr_authinit(ifs) 134f4b3ec61Sdh ipf_stack_t *ifs; 1357c478bd9Sstevel@tonic-gate { 136f4b3ec61Sdh KMALLOCS(ifs->ifs_fr_auth, frauth_t *, 137f4b3ec61Sdh ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 138f4b3ec61Sdh if (ifs->ifs_fr_auth != NULL) 139f4b3ec61Sdh bzero((char *)ifs->ifs_fr_auth, 140f4b3ec61Sdh ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 1417c478bd9Sstevel@tonic-gate else 1427c478bd9Sstevel@tonic-gate return -1; 1437c478bd9Sstevel@tonic-gate 144f4b3ec61Sdh KMALLOCS(ifs->ifs_fr_authpkts, mb_t **, 145f4b3ec61Sdh ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 146f4b3ec61Sdh if (ifs->ifs_fr_authpkts != NULL) 147f4b3ec61Sdh bzero((char *)ifs->ifs_fr_authpkts, 148f4b3ec61Sdh ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 1497c478bd9Sstevel@tonic-gate else 150ab25eeb5Syz return -2; 1517c478bd9Sstevel@tonic-gate 152f4b3ec61Sdh MUTEX_INIT(&ifs->ifs_ipf_authmx, "ipf auth log mutex"); 153f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_auth, "ipf IP User-Auth rwlock"); 154*af5f29ddSToomas Soome #if defined(SOLARIS) && defined(_KERNEL) 155f4b3ec61Sdh cv_init(&ifs->ifs_ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); 1567c478bd9Sstevel@tonic-gate #endif 157ab25eeb5Syz #if defined(linux) && defined(_KERNEL) 158ab25eeb5Syz init_waitqueue_head(&fr_authnext_linux); 159ab25eeb5Syz #endif 1607c478bd9Sstevel@tonic-gate 161f4b3ec61Sdh ifs->ifs_fr_auth_init = 1; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate return 0; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Check if a packet has authorization. If the packet is found to match an 1697c478bd9Sstevel@tonic-gate * authorization result and that would result in a feedback loop (i.e. it 1707c478bd9Sstevel@tonic-gate * will end up returning FR_AUTH) then return FR_BLOCK instead. 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate frentry_t *fr_checkauth(fin, passp) 1737c478bd9Sstevel@tonic-gate fr_info_t *fin; 1747c478bd9Sstevel@tonic-gate u_32_t *passp; 1757c478bd9Sstevel@tonic-gate { 1767c478bd9Sstevel@tonic-gate frentry_t *fr; 1777c478bd9Sstevel@tonic-gate frauth_t *fra; 1787c478bd9Sstevel@tonic-gate u_32_t pass; 1797c478bd9Sstevel@tonic-gate u_short id; 1807c478bd9Sstevel@tonic-gate ip_t *ip; 1817c478bd9Sstevel@tonic-gate int i; 182f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 1837c478bd9Sstevel@tonic-gate 184f4b3ec61Sdh if (ifs->ifs_fr_auth_lock || !ifs->ifs_fr_authused) 1857c478bd9Sstevel@tonic-gate return NULL; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate ip = fin->fin_ip; 1887c478bd9Sstevel@tonic-gate id = ip->ip_id; 1897c478bd9Sstevel@tonic-gate 190f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_auth); 191f4b3ec61Sdh for (i = ifs->ifs_fr_authstart; i != ifs->ifs_fr_authend; ) { 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * index becomes -2 only after an SIOCAUTHW. Check this in 1947c478bd9Sstevel@tonic-gate * case the same packet gets sent again and it hasn't yet been 1957c478bd9Sstevel@tonic-gate * auth'd. 1967c478bd9Sstevel@tonic-gate */ 197f4b3ec61Sdh fra = ifs->ifs_fr_auth + i; 1987c478bd9Sstevel@tonic-gate if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && 1997c478bd9Sstevel@tonic-gate !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * Avoid feedback loop. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) 2047c478bd9Sstevel@tonic-gate pass = FR_BLOCK; 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Create a dummy rule for the stateful checking to 2077c478bd9Sstevel@tonic-gate * use and return. Zero out any values we don't 2087c478bd9Sstevel@tonic-gate * trust from userland! 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && 2117c478bd9Sstevel@tonic-gate (fin->fin_flx & FI_FRAG))) { 2127c478bd9Sstevel@tonic-gate KMALLOC(fr, frentry_t *); 2137c478bd9Sstevel@tonic-gate if (fr) { 2147c478bd9Sstevel@tonic-gate bcopy((char *)fra->fra_info.fin_fr, 2157c478bd9Sstevel@tonic-gate (char *)fr, sizeof(*fr)); 2167c478bd9Sstevel@tonic-gate fr->fr_grp = NULL; 2177c478bd9Sstevel@tonic-gate fr->fr_ifa = fin->fin_ifp; 2187c478bd9Sstevel@tonic-gate fr->fr_func = NULL; 2197c478bd9Sstevel@tonic-gate fr->fr_ref = 1; 2207c478bd9Sstevel@tonic-gate fr->fr_flags = pass; 2217c478bd9Sstevel@tonic-gate fr->fr_ifas[1] = NULL; 2227c478bd9Sstevel@tonic-gate fr->fr_ifas[2] = NULL; 2237c478bd9Sstevel@tonic-gate fr->fr_ifas[3] = NULL; 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate } else 2267c478bd9Sstevel@tonic-gate fr = fra->fra_info.fin_fr; 2277c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 228f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 229f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 2307c478bd9Sstevel@tonic-gate if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { 231f4b3ec61Sdh fr->fr_next = ifs->ifs_fr_authlist; 232f4b3ec61Sdh ifs->ifs_fr_authlist = fr; 2337c478bd9Sstevel@tonic-gate } 234f4b3ec61Sdh ifs->ifs_fr_authstats.fas_hits++; 2357c478bd9Sstevel@tonic-gate fra->fra_index = -1; 236f4b3ec61Sdh ifs->ifs_fr_authused--; 237f4b3ec61Sdh if (i == ifs->ifs_fr_authstart) { 2387c478bd9Sstevel@tonic-gate while (fra->fra_index == -1) { 2397c478bd9Sstevel@tonic-gate i++; 2407c478bd9Sstevel@tonic-gate fra++; 241f4b3ec61Sdh if (i == ifs->ifs_fr_authsize) { 2427c478bd9Sstevel@tonic-gate i = 0; 243f4b3ec61Sdh fra = ifs->ifs_fr_auth; 2447c478bd9Sstevel@tonic-gate } 245f4b3ec61Sdh ifs->ifs_fr_authstart = i; 246f4b3ec61Sdh if (i == ifs->ifs_fr_authend) 2477c478bd9Sstevel@tonic-gate break; 2487c478bd9Sstevel@tonic-gate } 249f4b3ec61Sdh if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 250f4b3ec61Sdh ifs->ifs_fr_authnext = 0; 251f4b3ec61Sdh ifs->ifs_fr_authstart = 0; 252f4b3ec61Sdh ifs->ifs_fr_authend = 0; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate } 255f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 2567c478bd9Sstevel@tonic-gate if (passp != NULL) 2577c478bd9Sstevel@tonic-gate *passp = pass; 258f4b3ec61Sdh ATOMIC_INC64(ifs->ifs_fr_authstats.fas_hits); 2597c478bd9Sstevel@tonic-gate return fr; 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate i++; 262f4b3ec61Sdh if (i == ifs->ifs_fr_authsize) 2637c478bd9Sstevel@tonic-gate i = 0; 2647c478bd9Sstevel@tonic-gate } 265f4b3ec61Sdh ifs->ifs_fr_authstats.fas_miss++; 266f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 267f4b3ec61Sdh ATOMIC_INC64(ifs->ifs_fr_authstats.fas_miss); 2687c478bd9Sstevel@tonic-gate return NULL; 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * Check if we have room in the auth array to hold details for another packet. 2747c478bd9Sstevel@tonic-gate * If we do, store it and wake up any user programs which are waiting to 2757c478bd9Sstevel@tonic-gate * hear about these events. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate int fr_newauth(m, fin) 2787c478bd9Sstevel@tonic-gate mb_t *m; 2797c478bd9Sstevel@tonic-gate fr_info_t *fin; 2807c478bd9Sstevel@tonic-gate { 2817c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && defined(MENTAT) 282ab25eeb5Syz qpktinfo_t *qpi = fin->fin_qpi; 2837c478bd9Sstevel@tonic-gate #endif 2847c478bd9Sstevel@tonic-gate frauth_t *fra; 2857c478bd9Sstevel@tonic-gate #if !defined(sparc) && !defined(m68k) 2867c478bd9Sstevel@tonic-gate ip_t *ip; 2877c478bd9Sstevel@tonic-gate #endif 2887c478bd9Sstevel@tonic-gate int i; 289f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 2907c478bd9Sstevel@tonic-gate 291f4b3ec61Sdh if (ifs->ifs_fr_auth_lock) 2927c478bd9Sstevel@tonic-gate return 0; 2937c478bd9Sstevel@tonic-gate 294f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 295f4b3ec61Sdh if (ifs->ifs_fr_authstart > ifs->ifs_fr_authend) { 296f4b3ec61Sdh ifs->ifs_fr_authstats.fas_nospace++; 297f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 2987c478bd9Sstevel@tonic-gate return 0; 2997c478bd9Sstevel@tonic-gate } else { 300f4b3ec61Sdh if (ifs->ifs_fr_authused == ifs->ifs_fr_authsize) { 301f4b3ec61Sdh ifs->ifs_fr_authstats.fas_nospace++; 302f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 3037c478bd9Sstevel@tonic-gate return 0; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 307f4b3ec61Sdh ifs->ifs_fr_authstats.fas_added++; 308f4b3ec61Sdh ifs->ifs_fr_authused++; 309f4b3ec61Sdh i = ifs->ifs_fr_authend++; 310f4b3ec61Sdh if (ifs->ifs_fr_authend == ifs->ifs_fr_authsize) 311f4b3ec61Sdh ifs->ifs_fr_authend = 0; 312f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 3137c478bd9Sstevel@tonic-gate 314f4b3ec61Sdh fra = ifs->ifs_fr_auth + i; 3157c478bd9Sstevel@tonic-gate fra->fra_index = i; 3167c478bd9Sstevel@tonic-gate fra->fra_pass = 0; 317f4b3ec61Sdh fra->fra_age = ifs->ifs_fr_defaultauthage; 3187c478bd9Sstevel@tonic-gate bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); 3197c478bd9Sstevel@tonic-gate #if !defined(sparc) && !defined(m68k) 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * No need to copyback here as we want to undo the changes, not keep 3227c478bd9Sstevel@tonic-gate * them. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate ip = fin->fin_ip; 3257c478bd9Sstevel@tonic-gate # if defined(MENTAT) && defined(_KERNEL) 3267c478bd9Sstevel@tonic-gate if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) 3277c478bd9Sstevel@tonic-gate # endif 3287c478bd9Sstevel@tonic-gate { 3297c478bd9Sstevel@tonic-gate register u_short bo; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate bo = ip->ip_len; 3327c478bd9Sstevel@tonic-gate ip->ip_len = htons(bo); 3337c478bd9Sstevel@tonic-gate bo = ip->ip_off; 3347c478bd9Sstevel@tonic-gate ip->ip_off = htons(bo); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate #endif 337*af5f29ddSToomas Soome #if defined(SOLARIS) && defined(_KERNEL) 338ab25eeb5Syz m->b_rptr -= qpi->qpi_off; 339f4b3ec61Sdh ifs->ifs_fr_authpkts[i] = *(mblk_t **)fin->fin_mp; 340f4b3ec61Sdh cv_signal(&ifs->ifs_ipfauthwait); 3417c478bd9Sstevel@tonic-gate #else 3427c478bd9Sstevel@tonic-gate # if defined(BSD) && !defined(sparc) && (BSD >= 199306) 3437c478bd9Sstevel@tonic-gate if (!fin->fin_out) { 3447c478bd9Sstevel@tonic-gate ip->ip_len = htons(ip->ip_len); 3457c478bd9Sstevel@tonic-gate ip->ip_off = htons(ip->ip_off); 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate # endif 348f4b3ec61Sdh ifs->ifs_fr_authpkts[i] = m; 349f4b3ec61Sdh WAKEUP(&ifs->ifs_fr_authnext, 0); 3507c478bd9Sstevel@tonic-gate #endif 3517c478bd9Sstevel@tonic-gate return 1; 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate 355f4b3ec61Sdh int fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs) 3567c478bd9Sstevel@tonic-gate caddr_t data; 357ab25eeb5Syz ioctlcmd_t cmd; 358f4b3ec61Sdh int mode,uid; 359f4b3ec61Sdh void *ctx; 360f4b3ec61Sdh ipf_stack_t *ifs; 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate mb_t *m; 363ab25eeb5Syz #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ 364ab25eeb5Syz (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) 3657c478bd9Sstevel@tonic-gate struct ifqueue *ifq; 366ab25eeb5Syz SPL_INT(s); 3677c478bd9Sstevel@tonic-gate #endif 3687c478bd9Sstevel@tonic-gate frauth_t auth, *au = &auth, *fra; 3697c478bd9Sstevel@tonic-gate int i, error = 0, len; 3707c478bd9Sstevel@tonic-gate char *t; 3717ddc9b1aSDarren Reed net_handle_t net_data_p; 372381a2a9aSdr net_inject_t inj_data; 373381a2a9aSdr int ret; 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate switch (cmd) 3767c478bd9Sstevel@tonic-gate { 377f4b3ec61Sdh case SIOCGENITER : 378f4b3ec61Sdh { 379f4b3ec61Sdh ipftoken_t *token; 380f4b3ec61Sdh ipfgeniter_t iter; 381f4b3ec61Sdh 382f4b3ec61Sdh error = fr_inobj(data, &iter, IPFOBJ_GENITER); 383f4b3ec61Sdh if (error != 0) 384f4b3ec61Sdh break; 385f4b3ec61Sdh 386f4b3ec61Sdh token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx, ifs); 387f4b3ec61Sdh if (token != NULL) 388f4b3ec61Sdh error = fr_authgeniter(token, &iter, ifs); 389f4b3ec61Sdh else 390f4b3ec61Sdh error = ESRCH; 391f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 392f4b3ec61Sdh 393f4b3ec61Sdh break; 394f4b3ec61Sdh } 395f4b3ec61Sdh 3967c478bd9Sstevel@tonic-gate case SIOCSTLCK : 3977c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 3987c478bd9Sstevel@tonic-gate error = EPERM; 3997c478bd9Sstevel@tonic-gate break; 4007c478bd9Sstevel@tonic-gate } 401bb1d9de5SJohn Ojemann error = fr_lock(data, &ifs->ifs_fr_auth_lock); 4027c478bd9Sstevel@tonic-gate break; 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate case SIOCATHST: 405f4b3ec61Sdh ifs->ifs_fr_authstats.fas_faelist = ifs->ifs_fae_list; 406f4b3ec61Sdh error = fr_outobj(data, &ifs->ifs_fr_authstats, 407f4b3ec61Sdh IPFOBJ_AUTHSTAT); 4087c478bd9Sstevel@tonic-gate break; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate case SIOCIPFFL: 4117c478bd9Sstevel@tonic-gate SPL_NET(s); 412f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 413f4b3ec61Sdh i = fr_authflush(ifs); 414f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4157c478bd9Sstevel@tonic-gate SPL_X(s); 4167c478bd9Sstevel@tonic-gate error = copyoutptr((char *)&i, data, sizeof(i)); 4177c478bd9Sstevel@tonic-gate break; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate case SIOCAUTHW: 4207c478bd9Sstevel@tonic-gate fr_authioctlloop: 4217c478bd9Sstevel@tonic-gate error = fr_inobj(data, au, IPFOBJ_FRAUTH); 422f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_auth); 423f4b3ec61Sdh if ((ifs->ifs_fr_authnext != ifs->ifs_fr_authend) && 424f4b3ec61Sdh ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]) { 425f4b3ec61Sdh error = fr_outobj(data, 426f4b3ec61Sdh &ifs->ifs_fr_auth[ifs->ifs_fr_authnext], 4277c478bd9Sstevel@tonic-gate IPFOBJ_FRAUTH); 4287c478bd9Sstevel@tonic-gate if (auth.fra_len != 0 && auth.fra_buf != NULL) { 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * Copy packet contents out to user space if 4317c478bd9Sstevel@tonic-gate * requested. Bail on an error. 4327c478bd9Sstevel@tonic-gate */ 433f4b3ec61Sdh m = ifs->ifs_fr_authpkts[ifs->ifs_fr_authnext]; 4347c478bd9Sstevel@tonic-gate len = MSGDSIZE(m); 4357c478bd9Sstevel@tonic-gate if (len > auth.fra_len) 4367c478bd9Sstevel@tonic-gate len = auth.fra_len; 4377c478bd9Sstevel@tonic-gate auth.fra_len = len; 4387c478bd9Sstevel@tonic-gate for (t = auth.fra_buf; m && (len > 0); ) { 4397c478bd9Sstevel@tonic-gate i = MIN(M_LEN(m), len); 4407c478bd9Sstevel@tonic-gate error = copyoutptr(MTOD(m, char *), 4417c478bd9Sstevel@tonic-gate t, i); 4427c478bd9Sstevel@tonic-gate len -= i; 4437c478bd9Sstevel@tonic-gate t += i; 4447c478bd9Sstevel@tonic-gate if (error != 0) 4457c478bd9Sstevel@tonic-gate break; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate } 448f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4497c478bd9Sstevel@tonic-gate if (error != 0) 4507c478bd9Sstevel@tonic-gate break; 4517c478bd9Sstevel@tonic-gate SPL_NET(s); 452f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 453f4b3ec61Sdh ifs->ifs_fr_authnext++; 454f4b3ec61Sdh if (ifs->ifs_fr_authnext == ifs->ifs_fr_authsize) 455f4b3ec61Sdh ifs->ifs_fr_authnext = 0; 456f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4577c478bd9Sstevel@tonic-gate SPL_X(s); 4587c478bd9Sstevel@tonic-gate return 0; 4597c478bd9Sstevel@tonic-gate } 460f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 4617c478bd9Sstevel@tonic-gate /* 4627c478bd9Sstevel@tonic-gate * We exit ipf_global here because a program that enters in 4637c478bd9Sstevel@tonic-gate * here will have a lock on it and goto sleep having this lock. 4647c478bd9Sstevel@tonic-gate * If someone were to do an 'ipf -D' the system would then 4657c478bd9Sstevel@tonic-gate * deadlock. The catch with releasing it here is that the 4667c478bd9Sstevel@tonic-gate * caller of this function expects it to be held when we 4677c478bd9Sstevel@tonic-gate * return so we have to reacquire it in here. 4687c478bd9Sstevel@tonic-gate */ 469f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 4707c478bd9Sstevel@tonic-gate 471f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_authmx); 4727c478bd9Sstevel@tonic-gate #ifdef _KERNEL 4737c478bd9Sstevel@tonic-gate # if SOLARIS 4747c478bd9Sstevel@tonic-gate error = 0; 475f4b3ec61Sdh if (!cv_wait_sig(&ifs->ifs_ipfauthwait, &ifs->ifs_ipf_authmx.ipf_lk)) 4767c478bd9Sstevel@tonic-gate error = EINTR; 4777c478bd9Sstevel@tonic-gate # else /* SOLARIS */ 4787c478bd9Sstevel@tonic-gate # ifdef __hpux 4797c478bd9Sstevel@tonic-gate { 4807c478bd9Sstevel@tonic-gate lock_t *l; 4817c478bd9Sstevel@tonic-gate 482f4b3ec61Sdh l = get_sleep_lock(&ifs->ifs_fr_authnext); 483f4b3ec61Sdh error = sleep(&ifs->ifs_fr_authnext, PZERO+1); 4847c478bd9Sstevel@tonic-gate spinunlock(l); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate # else 4877c478bd9Sstevel@tonic-gate # ifdef __osf__ 488f4b3ec61Sdh error = mpsleep(&ifs->ifs_fr_authnext, PSUSP|PCATCH, 489f4b3ec61Sdh "fr_authnext", 0, 490f4b3ec61Sdh &ifs->ifs_ipf_authmx, MS_LOCK_SIMPLE); 4917c478bd9Sstevel@tonic-gate # else 492f4b3ec61Sdh error = SLEEP(&ifs->ifs_fr_authnext, "fr_authnext"); 4937c478bd9Sstevel@tonic-gate # endif /* __osf__ */ 4947c478bd9Sstevel@tonic-gate # endif /* __hpux */ 4957c478bd9Sstevel@tonic-gate # endif /* SOLARIS */ 4967c478bd9Sstevel@tonic-gate #endif 497f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_authmx); 498f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 4997c478bd9Sstevel@tonic-gate if (error == 0) { 500f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_auth); 5017c478bd9Sstevel@tonic-gate goto fr_authioctlloop; 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate break; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate case SIOCAUTHR: 5067c478bd9Sstevel@tonic-gate error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); 5077c478bd9Sstevel@tonic-gate if (error != 0) 5087c478bd9Sstevel@tonic-gate return error; 5097c478bd9Sstevel@tonic-gate SPL_NET(s); 510f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 5117c478bd9Sstevel@tonic-gate i = au->fra_index; 512f4b3ec61Sdh fra = ifs->ifs_fr_auth + i; 513f4b3ec61Sdh if ((i < 0) || (i >= ifs->ifs_fr_authsize) || 5147c478bd9Sstevel@tonic-gate (fra->fra_info.fin_id != au->fra_info.fin_id)) { 515f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 5167c478bd9Sstevel@tonic-gate SPL_X(s); 5177c478bd9Sstevel@tonic-gate return ESRCH; 5187c478bd9Sstevel@tonic-gate } 519f4b3ec61Sdh m = ifs->ifs_fr_authpkts[i]; 5207c478bd9Sstevel@tonic-gate fra->fra_index = -2; 5217c478bd9Sstevel@tonic-gate fra->fra_pass = au->fra_pass; 522f4b3ec61Sdh ifs->ifs_fr_authpkts[i] = NULL; 523f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 5247c478bd9Sstevel@tonic-gate #ifdef _KERNEL 525381a2a9aSdr if (fra->fra_info.fin_v == 4) { 526f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 527381a2a9aSdr } else if (fra->fra_info.fin_v == 6) { 528f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 529381a2a9aSdr } else { 530381a2a9aSdr return (-1); 531381a2a9aSdr } 532381a2a9aSdr 533381a2a9aSdr /* 534381a2a9aSdr * We're putting the packet back on the same interface 535381a2a9aSdr * queue that it was originally seen on so that it can 536381a2a9aSdr * progress through the system properly, with the result 537381a2a9aSdr * of the auth check done. 538381a2a9aSdr */ 539381a2a9aSdr inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp; 540381a2a9aSdr 5417c478bd9Sstevel@tonic-gate if ((m != NULL) && (au->fra_info.fin_out != 0)) { 5427c478bd9Sstevel@tonic-gate # ifdef MENTAT 543381a2a9aSdr inj_data.ni_packet = m; 544381a2a9aSdr ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data); 545381a2a9aSdr 546381a2a9aSdr if (ret < 0) 547f4b3ec61Sdh ifs->ifs_fr_authstats.fas_sendfail++; 548381a2a9aSdr else 549f4b3ec61Sdh ifs->ifs_fr_authstats.fas_sendok++; 5507c478bd9Sstevel@tonic-gate # else /* MENTAT */ 551ab25eeb5Syz # if defined(linux) || defined(AIX) 552ab25eeb5Syz # else 553ab25eeb5Syz # if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ 554ab25eeb5Syz (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \ 555ab25eeb5Syz (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) 5567c478bd9Sstevel@tonic-gate error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, 5577c478bd9Sstevel@tonic-gate NULL); 558ab25eeb5Syz # else 5597c478bd9Sstevel@tonic-gate error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); 560ab25eeb5Syz # endif 5617c478bd9Sstevel@tonic-gate if (error != 0) 562f4b3ec61Sdh ifs->ifs_fr_authstats.fas_sendfail++; 5637c478bd9Sstevel@tonic-gate else 564f4b3ec61Sdh ifs->ifs_fr_authstats.fas_sendok++; 565381a2a9aSdr # endif /* Linux */ 566381a2a9aSdr # endif /* MENTAT */ 5677c478bd9Sstevel@tonic-gate } else if (m) { 5687c478bd9Sstevel@tonic-gate # ifdef MENTAT 569381a2a9aSdr inj_data.ni_packet = m; 570381a2a9aSdr ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data); 5717c478bd9Sstevel@tonic-gate # else /* MENTAT */ 572ab25eeb5Syz # if defined(linux) || defined(AIX) 573ab25eeb5Syz # else 574ab25eeb5Syz # if (__FreeBSD_version >= 501000) 575ab25eeb5Syz netisr_dispatch(NETISR_IP, m); 576ab25eeb5Syz # else 577ab25eeb5Syz # if (IRIX >= 60516) 578ab25eeb5Syz ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; 579ab25eeb5Syz # else 5807c478bd9Sstevel@tonic-gate ifq = &ipintrq; 581ab25eeb5Syz # endif 5827c478bd9Sstevel@tonic-gate if (IF_QFULL(ifq)) { 5837c478bd9Sstevel@tonic-gate IF_DROP(ifq); 584ab25eeb5Syz FREE_MB_T(m); 5857c478bd9Sstevel@tonic-gate error = ENOBUFS; 5867c478bd9Sstevel@tonic-gate } else { 5877c478bd9Sstevel@tonic-gate IF_ENQUEUE(ifq, m); 588ab25eeb5Syz # if IRIX < 60500 5897c478bd9Sstevel@tonic-gate schednetisr(NETISR_IP); 590ab25eeb5Syz # endif 5917c478bd9Sstevel@tonic-gate } 592ab25eeb5Syz # endif 593ab25eeb5Syz # endif /* Linux */ 5947c478bd9Sstevel@tonic-gate # endif /* MENTAT */ 5957c478bd9Sstevel@tonic-gate if (error != 0) 596f4b3ec61Sdh ifs->ifs_fr_authstats.fas_quefail++; 5977c478bd9Sstevel@tonic-gate else 598f4b3ec61Sdh ifs->ifs_fr_authstats.fas_queok++; 5997c478bd9Sstevel@tonic-gate } else 6007c478bd9Sstevel@tonic-gate error = EINVAL; 6017c478bd9Sstevel@tonic-gate # ifdef MENTAT 6027c478bd9Sstevel@tonic-gate if (error != 0) 6037c478bd9Sstevel@tonic-gate error = EINVAL; 6047c478bd9Sstevel@tonic-gate # else /* MENTAT */ 6057c478bd9Sstevel@tonic-gate /* 6067c478bd9Sstevel@tonic-gate * If we experience an error which will result in the packet 6077c478bd9Sstevel@tonic-gate * not being processed, make sure we advance to the next one. 608ab25eeb5Syz */ 6097c478bd9Sstevel@tonic-gate if (error == ENOBUFS) { 610f4b3ec61Sdh ifs->ifs_fr_authused--; 6117c478bd9Sstevel@tonic-gate fra->fra_index = -1; 6127c478bd9Sstevel@tonic-gate fra->fra_pass = 0; 613f4b3ec61Sdh if (i == ifs->ifs_fr_authstart) { 6147c478bd9Sstevel@tonic-gate while (fra->fra_index == -1) { 6157c478bd9Sstevel@tonic-gate i++; 616f4b3ec61Sdh if (i == ifs->ifs_fr_authsize) 6177c478bd9Sstevel@tonic-gate i = 0; 618f4b3ec61Sdh ifs->ifs_fr_authstart = i; 619f4b3ec61Sdh if (i == ifs->ifs_fr_authend) 6207c478bd9Sstevel@tonic-gate break; 6217c478bd9Sstevel@tonic-gate } 622f4b3ec61Sdh if (ifs->ifs_fr_authstart == ifs->ifs_fr_authend) { 623f4b3ec61Sdh ifs->ifs_fr_authnext = 0; 624f4b3ec61Sdh ifs->ifs_fr_authstart = 0; 625f4b3ec61Sdh ifs->ifs_fr_authend = 0; 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate # endif /* MENTAT */ 6307c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 6317c478bd9Sstevel@tonic-gate SPL_X(s); 6327c478bd9Sstevel@tonic-gate break; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate default : 6357c478bd9Sstevel@tonic-gate error = EINVAL; 6367c478bd9Sstevel@tonic-gate break; 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate return error; 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * Free all network buffer memory used to keep saved packets. 6447c478bd9Sstevel@tonic-gate */ 645f4b3ec61Sdh void fr_authunload(ifs) 646f4b3ec61Sdh ipf_stack_t *ifs; 6477c478bd9Sstevel@tonic-gate { 6487c478bd9Sstevel@tonic-gate register int i; 6497c478bd9Sstevel@tonic-gate register frauthent_t *fae, **faep; 6507c478bd9Sstevel@tonic-gate frentry_t *fr, **frp; 6517c478bd9Sstevel@tonic-gate mb_t *m; 6527c478bd9Sstevel@tonic-gate 653f4b3ec61Sdh if (ifs->ifs_fr_auth != NULL) { 654f4b3ec61Sdh KFREES(ifs->ifs_fr_auth, 655f4b3ec61Sdh ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_auth)); 656f4b3ec61Sdh ifs->ifs_fr_auth = NULL; 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 659f4b3ec61Sdh if (ifs->ifs_fr_authpkts != NULL) { 660f4b3ec61Sdh for (i = 0; i < ifs->ifs_fr_authsize; i++) { 661f4b3ec61Sdh m = ifs->ifs_fr_authpkts[i]; 6627c478bd9Sstevel@tonic-gate if (m != NULL) { 6637c478bd9Sstevel@tonic-gate FREE_MB_T(m); 664f4b3ec61Sdh ifs->ifs_fr_authpkts[i] = NULL; 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate } 667f4b3ec61Sdh KFREES(ifs->ifs_fr_authpkts, 668f4b3ec61Sdh ifs->ifs_fr_authsize * sizeof(*ifs->ifs_fr_authpkts)); 669f4b3ec61Sdh ifs->ifs_fr_authpkts = NULL; 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 672f4b3ec61Sdh faep = &ifs->ifs_fae_list; 6737c478bd9Sstevel@tonic-gate while ((fae = *faep) != NULL) { 6747c478bd9Sstevel@tonic-gate *faep = fae->fae_next; 6757c478bd9Sstevel@tonic-gate KFREE(fae); 6767c478bd9Sstevel@tonic-gate } 677f4b3ec61Sdh ifs->ifs_ipauth = NULL; 6787c478bd9Sstevel@tonic-gate 679f4b3ec61Sdh if (ifs->ifs_fr_authlist != NULL) { 680f4b3ec61Sdh for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 6817c478bd9Sstevel@tonic-gate if (fr->fr_ref == 1) { 6827c478bd9Sstevel@tonic-gate *frp = fr->fr_next; 6837c478bd9Sstevel@tonic-gate KFREE(fr); 6847c478bd9Sstevel@tonic-gate } else 6857c478bd9Sstevel@tonic-gate frp = &fr->fr_next; 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate 689f4b3ec61Sdh if (ifs->ifs_fr_auth_init == 1) { 690*af5f29ddSToomas Soome # if defined(SOLARIS) && defined(_KERNEL) 691f4b3ec61Sdh cv_destroy(&ifs->ifs_ipfauthwait); 6927c478bd9Sstevel@tonic-gate # endif 693f4b3ec61Sdh MUTEX_DESTROY(&ifs->ifs_ipf_authmx); 694f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_auth); 6957c478bd9Sstevel@tonic-gate 696f4b3ec61Sdh ifs->ifs_fr_auth_init = 0; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Slowly expire held auth records. Timeouts are set 7037c478bd9Sstevel@tonic-gate * in expectation of this being called twice per second. 7047c478bd9Sstevel@tonic-gate */ 705f4b3ec61Sdh void fr_authexpire(ifs) 706f4b3ec61Sdh ipf_stack_t *ifs; 7077c478bd9Sstevel@tonic-gate { 7087c478bd9Sstevel@tonic-gate register int i; 7097c478bd9Sstevel@tonic-gate register frauth_t *fra; 7107c478bd9Sstevel@tonic-gate register frauthent_t *fae, **faep; 7117c478bd9Sstevel@tonic-gate register frentry_t *fr, **frp; 7127c478bd9Sstevel@tonic-gate mb_t *m; 713ab25eeb5Syz SPL_INT(s); 7147c478bd9Sstevel@tonic-gate 715f4b3ec61Sdh if (ifs->ifs_fr_auth_lock) 7167c478bd9Sstevel@tonic-gate return; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate SPL_NET(s); 719f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 720f4b3ec61Sdh for (i = 0, fra = ifs->ifs_fr_auth; i < ifs->ifs_fr_authsize; i++, fra++) { 7217c478bd9Sstevel@tonic-gate fra->fra_age--; 722f4b3ec61Sdh if ((fra->fra_age == 0) && (m = ifs->ifs_fr_authpkts[i])) { 7237c478bd9Sstevel@tonic-gate FREE_MB_T(m); 724f4b3ec61Sdh ifs->ifs_fr_authpkts[i] = NULL; 725f4b3ec61Sdh ifs->ifs_fr_auth[i].fra_index = -1; 726f4b3ec61Sdh ifs->ifs_fr_authstats.fas_expire++; 727f4b3ec61Sdh ifs->ifs_fr_authused--; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 731f4b3ec61Sdh for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 7327c478bd9Sstevel@tonic-gate fae->fae_age--; 7337c478bd9Sstevel@tonic-gate if (fae->fae_age == 0) { 7347c478bd9Sstevel@tonic-gate *faep = fae->fae_next; 7357c478bd9Sstevel@tonic-gate KFREE(fae); 736f4b3ec61Sdh ifs->ifs_fr_authstats.fas_expire++; 7377c478bd9Sstevel@tonic-gate } else 7387c478bd9Sstevel@tonic-gate faep = &fae->fae_next; 7397c478bd9Sstevel@tonic-gate } 740f4b3ec61Sdh if (ifs->ifs_fae_list != NULL) 741f4b3ec61Sdh ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 7427c478bd9Sstevel@tonic-gate else 743f4b3ec61Sdh ifs->ifs_ipauth = NULL; 7447c478bd9Sstevel@tonic-gate 745f4b3ec61Sdh for (frp = &ifs->ifs_fr_authlist; ((fr = *frp) != NULL); ) { 7467c478bd9Sstevel@tonic-gate if (fr->fr_ref == 1) { 7477c478bd9Sstevel@tonic-gate *frp = fr->fr_next; 7487c478bd9Sstevel@tonic-gate KFREE(fr); 7497c478bd9Sstevel@tonic-gate } else 7507c478bd9Sstevel@tonic-gate frp = &fr->fr_next; 7517c478bd9Sstevel@tonic-gate } 752f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 7537c478bd9Sstevel@tonic-gate SPL_X(s); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 756f4b3ec61Sdh int fr_preauthcmd(cmd, fr, frptr, ifs) 757ab25eeb5Syz ioctlcmd_t cmd; 7587c478bd9Sstevel@tonic-gate frentry_t *fr, **frptr; 759f4b3ec61Sdh ipf_stack_t *ifs; 7607c478bd9Sstevel@tonic-gate { 7617c478bd9Sstevel@tonic-gate frauthent_t *fae, **faep; 7627c478bd9Sstevel@tonic-gate int error = 0; 763ab25eeb5Syz SPL_INT(s); 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) 7667c478bd9Sstevel@tonic-gate return EIO; 7677c478bd9Sstevel@tonic-gate 768f4b3ec61Sdh for (faep = &ifs->ifs_fae_list; ((fae = *faep) != NULL); ) { 7697c478bd9Sstevel@tonic-gate if (&fae->fae_fr == fr) 7707c478bd9Sstevel@tonic-gate break; 7717c478bd9Sstevel@tonic-gate else 7727c478bd9Sstevel@tonic-gate faep = &fae->fae_next; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 775ab25eeb5Syz if (cmd == (ioctlcmd_t)SIOCRMAFR) { 7767c478bd9Sstevel@tonic-gate if (fr == NULL || frptr == NULL) 7777c478bd9Sstevel@tonic-gate error = EINVAL; 7787c478bd9Sstevel@tonic-gate else if (fae == NULL) 7797c478bd9Sstevel@tonic-gate error = ESRCH; 7807c478bd9Sstevel@tonic-gate else { 7817c478bd9Sstevel@tonic-gate SPL_NET(s); 782f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 7837c478bd9Sstevel@tonic-gate *faep = fae->fae_next; 784f4b3ec61Sdh if (ifs->ifs_ipauth == &fae->fae_fr) 785f4b3ec61Sdh ifs->ifs_ipauth = ifs->ifs_fae_list ? 786f4b3ec61Sdh &ifs->ifs_fae_list->fae_fr : NULL; 787f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 7887c478bd9Sstevel@tonic-gate SPL_X(s); 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate KFREE(fae); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate } else if (fr != NULL && frptr != NULL) { 7937c478bd9Sstevel@tonic-gate KMALLOC(fae, frauthent_t *); 7947c478bd9Sstevel@tonic-gate if (fae != NULL) { 7957c478bd9Sstevel@tonic-gate bcopy((char *)fr, (char *)&fae->fae_fr, 7967c478bd9Sstevel@tonic-gate sizeof(*fr)); 7977c478bd9Sstevel@tonic-gate SPL_NET(s); 798f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_auth); 799f4b3ec61Sdh fae->fae_age = ifs->ifs_fr_defaultauthage; 8007c478bd9Sstevel@tonic-gate fae->fae_fr.fr_hits = 0; 8017c478bd9Sstevel@tonic-gate fae->fae_fr.fr_next = *frptr; 802f4b3ec61Sdh fae->fae_ref = 1; 8037c478bd9Sstevel@tonic-gate *frptr = &fae->fae_fr; 8047c478bd9Sstevel@tonic-gate fae->fae_next = *faep; 8057c478bd9Sstevel@tonic-gate *faep = fae; 806f4b3ec61Sdh ifs->ifs_ipauth = &ifs->ifs_fae_list->fae_fr; 807f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_auth); 8087c478bd9Sstevel@tonic-gate SPL_X(s); 8097c478bd9Sstevel@tonic-gate } else 8107c478bd9Sstevel@tonic-gate error = ENOMEM; 8117c478bd9Sstevel@tonic-gate } else 8127c478bd9Sstevel@tonic-gate error = EINVAL; 8137c478bd9Sstevel@tonic-gate return error; 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 818ab25eeb5Syz * Flush held packets. 819ab25eeb5Syz * Must already be properly SPL'ed and Locked on &ipf_auth. 820ab25eeb5Syz * 8217c478bd9Sstevel@tonic-gate */ 822f4b3ec61Sdh int fr_authflush(ifs) 823f4b3ec61Sdh ipf_stack_t *ifs; 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate register int i, num_flushed; 8267c478bd9Sstevel@tonic-gate mb_t *m; 8277c478bd9Sstevel@tonic-gate 828f4b3ec61Sdh if (ifs->ifs_fr_auth_lock) 8297c478bd9Sstevel@tonic-gate return -1; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate num_flushed = 0; 8327c478bd9Sstevel@tonic-gate 833f4b3ec61Sdh for (i = 0 ; i < ifs->ifs_fr_authsize; i++) { 834f4b3ec61Sdh m = ifs->ifs_fr_authpkts[i]; 8357c478bd9Sstevel@tonic-gate if (m != NULL) { 8367c478bd9Sstevel@tonic-gate FREE_MB_T(m); 837f4b3ec61Sdh ifs->ifs_fr_authpkts[i] = NULL; 838f4b3ec61Sdh ifs->ifs_fr_auth[i].fra_index = -1; 8397c478bd9Sstevel@tonic-gate /* perhaps add & use a flush counter inst.*/ 840f4b3ec61Sdh ifs->ifs_fr_authstats.fas_expire++; 841f4b3ec61Sdh ifs->ifs_fr_authused--; 8427c478bd9Sstevel@tonic-gate num_flushed++; 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 846f4b3ec61Sdh ifs->ifs_fr_authstart = 0; 847f4b3ec61Sdh ifs->ifs_fr_authend = 0; 848f4b3ec61Sdh ifs->ifs_fr_authnext = 0; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate return num_flushed; 8517c478bd9Sstevel@tonic-gate } 852f4b3ec61Sdh 853f4b3ec61Sdh /* ------------------------------------------------------------------------ */ 854f4b3ec61Sdh /* Function: fr_authgeniter */ 855f4b3ec61Sdh /* Returns: int - 0 == success, else error */ 856f4b3ec61Sdh /* Parameters: token(I) - pointer to ipftoken structure */ 857f4b3ec61Sdh /* itp(I) - pointer to ipfgeniter structure */ 858f4b3ec61Sdh /* */ 859f4b3ec61Sdh /* ------------------------------------------------------------------------ */ 860f4b3ec61Sdh int fr_authgeniter(token, itp, ifs) 861f4b3ec61Sdh ipftoken_t *token; 862f4b3ec61Sdh ipfgeniter_t *itp; 863f4b3ec61Sdh ipf_stack_t *ifs; 864f4b3ec61Sdh { 865f4b3ec61Sdh frauthent_t *fae, *next, zero; 866f4b3ec61Sdh int error; 867f4b3ec61Sdh 868f4b3ec61Sdh if (itp->igi_data == NULL) 869f4b3ec61Sdh return EFAULT; 870f4b3ec61Sdh 871f4b3ec61Sdh if (itp->igi_type != IPFGENITER_AUTH) 872f4b3ec61Sdh return EINVAL; 873f4b3ec61Sdh 874f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_auth); 875786c7074Sjojemann 876786c7074Sjojemann /* 877786c7074Sjojemann * Retrieve "previous" entry from token and find the next entry. 878786c7074Sjojemann */ 879786c7074Sjojemann fae = token->ipt_data; 880f4b3ec61Sdh if (fae == NULL) { 881f4b3ec61Sdh next = ifs->ifs_fae_list; 882f4b3ec61Sdh } else { 883f4b3ec61Sdh next = fae->fae_next; 884f4b3ec61Sdh } 885f4b3ec61Sdh 886786c7074Sjojemann /* 887786c7074Sjojemann * If we found an entry, add reference to it and update token. 888786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 889786c7074Sjojemann */ 890f4b3ec61Sdh if (next != NULL) { 891f4b3ec61Sdh ATOMIC_INC(next->fae_ref); 892786c7074Sjojemann token->ipt_data = next; 893f4b3ec61Sdh } else { 894f4b3ec61Sdh bzero(&zero, sizeof(zero)); 895f4b3ec61Sdh next = &zero; 896786c7074Sjojemann token->ipt_data = NULL; 897f4b3ec61Sdh } 898f4b3ec61Sdh 899f4b3ec61Sdh /* 900786c7074Sjojemann * Safe to release the lock now that we have a reference. 901f4b3ec61Sdh */ 902786c7074Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_auth); 903f4b3ec61Sdh 904f4b3ec61Sdh /* 905786c7074Sjojemann * Copy out the data and clean up references and token as needed. 906f4b3ec61Sdh */ 907f4b3ec61Sdh error = COPYOUT(next, itp->igi_data, sizeof(*next)); 908f4b3ec61Sdh if (error != 0) 909f4b3ec61Sdh error = EFAULT; 910786c7074Sjojemann if (token->ipt_data == NULL) { 911786c7074Sjojemann ipf_freetoken(token, ifs); 912786c7074Sjojemann } else { 913786c7074Sjojemann if (fae != NULL) { 914786c7074Sjojemann WRITE_ENTER(&ifs->ifs_ipf_auth); 915786c7074Sjojemann fr_authderef(&fae); 916786c7074Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_auth); 917786c7074Sjojemann } 918786c7074Sjojemann if (next->fae_next == NULL) 919786c7074Sjojemann ipf_freetoken(token, ifs); 920786c7074Sjojemann } 921f4b3ec61Sdh return error; 922f4b3ec61Sdh } 923f4b3ec61Sdh 924f4b3ec61Sdh 925f4b3ec61Sdh void fr_authderef(faep) 926f4b3ec61Sdh frauthent_t **faep; 927f4b3ec61Sdh { 928f4b3ec61Sdh frauthent_t *fae; 929f4b3ec61Sdh 930f4b3ec61Sdh fae = *faep; 931f4b3ec61Sdh *faep = NULL; 932f4b3ec61Sdh 933f4b3ec61Sdh fae->fae_ref--; 934f4b3ec61Sdh if (fae->fae_ref == 0) { 935f4b3ec61Sdh KFREE(fae); 936f4b3ec61Sdh } 937f4b3ec61Sdh } 938