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
fr_authinit(ifs)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");
154af5f29ddSToomas 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 */
fr_checkauth(fin,passp)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 */
fr_newauth(m,fin)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
337af5f29ddSToomas 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
fr_auth_ioctl(data,cmd,mode,uid,ctx,ifs)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
525*55fea89dSDan Cross if (fra->fra_info.fin_v == 4) {
526f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4;
527*55fea89dSDan Cross } else if (fra->fra_info.fin_v == 6) {
528f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6;
529*55fea89dSDan Cross } else {
530*55fea89dSDan Cross 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 */
fr_authunload(ifs)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) {
690af5f29ddSToomas 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 */
fr_authexpire(ifs)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
fr_preauthcmd(cmd,fr,frptr,ifs)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;
767*55fea89dSDan Cross
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 */
fr_authflush(ifs)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 /* ------------------------------------------------------------------------ */
fr_authgeniter(token,itp,ifs)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
fr_authderef(faep)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