Home | History | Annotate | Line # | Download | only in netinet
ip_auth.c revision 1.5.26.1
      1  1.5.26.1  pgoyette /*	$NetBSD: ip_auth.c,v 1.5.26.1 2018/05/21 04:36:14 pgoyette Exp $	*/
      2       1.1  christos 
      3       1.1  christos /*
      4       1.1  christos  * Copyright (C) 2012 by Darren Reed.
      5       1.1  christos  *
      6       1.1  christos  * See the IPFILTER.LICENCE file for details on licencing.
      7       1.1  christos  */
      8       1.1  christos #if defined(KERNEL) || defined(_KERNEL)
      9       1.1  christos # undef KERNEL
     10       1.1  christos # undef _KERNEL
     11       1.1  christos # define        KERNEL	1
     12       1.1  christos # define        _KERNEL	1
     13       1.1  christos #endif
     14       1.5     rmind #if defined(__NetBSD__)
     15       1.5     rmind #include <sys/cdefs.h>
     16       1.5     rmind #endif
     17       1.1  christos #include <sys/errno.h>
     18       1.1  christos #include <sys/types.h>
     19       1.1  christos #include <sys/param.h>
     20       1.1  christos #include <sys/time.h>
     21       1.1  christos #include <sys/file.h>
     22       1.1  christos #if !defined(_KERNEL)
     23       1.1  christos # include <stdio.h>
     24       1.1  christos # include <stdlib.h>
     25       1.1  christos # ifdef _STDC_C99
     26       1.1  christos #  include <stdbool.h>
     27       1.1  christos # endif
     28       1.1  christos # include <string.h>
     29       1.1  christos # define _KERNEL
     30       1.1  christos # ifdef __OpenBSD__
     31       1.1  christos struct file;
     32       1.1  christos # endif
     33       1.1  christos # include <sys/uio.h>
     34       1.1  christos # undef _KERNEL
     35       1.1  christos #endif
     36       1.1  christos #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
     37       1.1  christos # include <sys/filio.h>
     38       1.1  christos # include <sys/fcntl.h>
     39       1.1  christos #else
     40       1.1  christos # include <sys/ioctl.h>
     41       1.1  christos #endif
     42       1.1  christos #if !defined(linux)
     43       1.1  christos # include <sys/protosw.h>
     44       1.1  christos #endif
     45       1.1  christos #include <sys/socket.h>
     46       1.1  christos #if defined(_KERNEL)
     47       1.1  christos # include <sys/systm.h>
     48       1.1  christos # if !defined(__SVR4) && !defined(__svr4__) && !defined(linux)
     49       1.1  christos #  include <sys/mbuf.h>
     50       1.1  christos # endif
     51       1.1  christos #endif
     52       1.1  christos #if defined(__SVR4) || defined(__svr4__)
     53       1.1  christos # include <sys/filio.h>
     54       1.1  christos # include <sys/byteorder.h>
     55       1.1  christos # ifdef _KERNEL
     56       1.1  christos #  include <sys/dditypes.h>
     57       1.1  christos # endif
     58       1.1  christos # include <sys/stream.h>
     59       1.1  christos # include <sys/kmem.h>
     60       1.1  christos #endif
     61       1.1  christos #if (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) || \
     62       1.1  christos     (defined(__FreeBSD_version) &&(__FreeBSD_version >= 400000))
     63       1.1  christos # include <sys/queue.h>
     64       1.1  christos #endif
     65       1.1  christos #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
     66       1.1  christos # include <machine/cpu.h>
     67       1.1  christos #endif
     68       1.1  christos #if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
     69       1.1  christos # include <sys/proc.h>
     70       1.1  christos #endif
     71       1.1  christos #if defined(__NetBSD_Version__) &&  (__NetBSD_Version__ >= 400000) && \
     72       1.1  christos      !defined(_KERNEL)
     73       1.1  christos # include <stdbool.h>
     74       1.1  christos #endif
     75       1.1  christos #include <net/if.h>
     76       1.2  christos #include <net/route.h>
     77       1.1  christos #ifdef sun
     78       1.1  christos # include <net/af.h>
     79       1.1  christos #endif
     80       1.1  christos #include <netinet/in.h>
     81       1.1  christos #include <netinet/in_systm.h>
     82       1.1  christos #include <netinet/ip.h>
     83       1.1  christos #if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi)
     84       1.1  christos # define	KERNEL
     85       1.1  christos # define	_KERNEL
     86       1.1  christos # define	NOT_KERNEL
     87       1.1  christos #endif
     88       1.1  christos #if !defined(linux)
     89       1.1  christos # include <netinet/ip_var.h>
     90       1.1  christos #endif
     91       1.1  christos #ifdef	NOT_KERNEL
     92       1.1  christos # undef	_KERNEL
     93       1.1  christos # undef	KERNEL
     94       1.1  christos #endif
     95       1.1  christos #include <netinet/tcp.h>
     96       1.1  christos #if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */
     97       1.1  christos extern struct ifqueue   ipintrq;		/* ip packet input queue */
     98       1.1  christos #else
     99       1.1  christos # if !defined(__hpux) && !defined(linux)
    100       1.1  christos #  if __FreeBSD_version >= 300000
    101       1.1  christos #   include <net/if_var.h>
    102       1.1  christos #   if __FreeBSD_version >= 500042
    103       1.1  christos #    define IF_QFULL _IF_QFULL
    104       1.1  christos #    define IF_DROP _IF_DROP
    105       1.1  christos #   endif /* __FreeBSD_version >= 500042 */
    106       1.1  christos #  endif
    107       1.1  christos #  include <netinet/in_var.h>
    108       1.1  christos #  include <netinet/tcp_fsm.h>
    109       1.1  christos # endif
    110       1.1  christos #endif
    111       1.1  christos #include <netinet/udp.h>
    112       1.1  christos #include <netinet/ip_icmp.h>
    113       1.1  christos #include "netinet/ip_compat.h"
    114       1.1  christos #include "netinet/ip_fil.h"
    115       1.1  christos #include "netinet/ip_auth.h"
    116       1.1  christos #if !defined(MENTAT) && !defined(linux)
    117       1.1  christos # include <net/netisr.h>
    118       1.1  christos # ifdef __FreeBSD__
    119       1.1  christos #  include <machine/cpufunc.h>
    120       1.1  christos # endif
    121       1.1  christos #endif
    122       1.1  christos #if (__FreeBSD_version >= 300000)
    123       1.1  christos # include <sys/malloc.h>
    124       1.1  christos # if defined(_KERNEL) && !defined(IPFILTER_LKM)
    125       1.1  christos #  include <sys/libkern.h>
    126       1.1  christos #  include <sys/systm.h>
    127       1.1  christos # endif
    128       1.1  christos #endif
    129       1.1  christos /* END OF INCLUDES */
    130       1.1  christos 
    131       1.1  christos #if !defined(lint)
    132       1.2  christos #if defined(__NetBSD__)
    133  1.5.26.1  pgoyette __KERNEL_RCSID(0, "$NetBSD: ip_auth.c,v 1.5.26.1 2018/05/21 04:36:14 pgoyette Exp $");
    134       1.2  christos #else
    135       1.3   darrenr static const char rcsid[] = "@(#)Id: ip_auth.c,v 1.1.1.2 2012/07/22 13:45:08 darrenr Exp";
    136       1.2  christos #endif
    137       1.1  christos #endif
    138       1.1  christos 
    139       1.1  christos 
    140       1.1  christos typedef	struct ipf_auth_softc_s {
    141       1.1  christos #if SOLARIS && defined(_KERNEL)
    142       1.1  christos 	kcondvar_t	ipf_auth_wait;
    143       1.1  christos #endif /* SOLARIS */
    144       1.1  christos #if defined(linux) && defined(_KERNEL)
    145       1.1  christos 	wait_queue_head_t ipf_auth_next_linux;
    146       1.1  christos #endif
    147       1.1  christos 	ipfrwlock_t	ipf_authlk;
    148       1.1  christos 	ipfmutex_t	ipf_auth_mx;
    149       1.1  christos 	int		ipf_auth_size;
    150       1.1  christos 	int		ipf_auth_used;
    151       1.1  christos 	int		ipf_auth_replies;
    152       1.1  christos 	int		ipf_auth_defaultage;
    153       1.1  christos 	int		ipf_auth_lock;
    154       1.1  christos 	ipf_authstat_t	ipf_auth_stats;
    155       1.1  christos 	frauth_t	*ipf_auth;
    156       1.1  christos 	mb_t		**ipf_auth_pkts;
    157       1.1  christos 	int		ipf_auth_start;
    158       1.1  christos 	int		ipf_auth_end;
    159       1.1  christos 	int		ipf_auth_next;
    160       1.1  christos 	frauthent_t	*ipf_auth_entries;
    161       1.1  christos 	frentry_t	*ipf_auth_ip;
    162       1.1  christos 	frentry_t	*ipf_auth_rules;
    163       1.1  christos } ipf_auth_softc_t;
    164       1.1  christos 
    165       1.1  christos 
    166       1.2  christos static void ipf_auth_deref(frauthent_t **);
    167       1.2  christos static void ipf_auth_deref_unlocked(ipf_auth_softc_t *, frauthent_t **);
    168       1.2  christos static int ipf_auth_geniter(ipf_main_softc_t *, ipftoken_t *,
    169       1.2  christos 				 ipfgeniter_t *, ipfobj_t *);
    170       1.2  christos static int ipf_auth_reply(ipf_main_softc_t *, ipf_auth_softc_t *, char *);
    171       1.2  christos static int ipf_auth_wait(ipf_main_softc_t *, ipf_auth_softc_t *, char *);
    172       1.2  christos static int ipf_auth_flush(void *);
    173       1.1  christos 
    174       1.1  christos 
    175       1.1  christos /* ------------------------------------------------------------------------ */
    176       1.1  christos /* Function:    ipf_auth_main_load                                          */
    177       1.1  christos /* Returns:     int - 0 == success, else error                              */
    178       1.1  christos /* Parameters:  None                                                        */
    179       1.1  christos /*                                                                          */
    180       1.1  christos /* A null-op function that exists as a placeholder so that the flow in      */
    181       1.1  christos /* other functions is obvious.                                              */
    182       1.1  christos /* ------------------------------------------------------------------------ */
    183       1.1  christos int
    184       1.2  christos ipf_auth_main_load(void)
    185       1.1  christos {
    186       1.1  christos 	return 0;
    187       1.1  christos }
    188       1.1  christos 
    189       1.1  christos 
    190       1.1  christos /* ------------------------------------------------------------------------ */
    191       1.1  christos /* Function:    ipf_auth_main_unload                                        */
    192       1.1  christos /* Returns:     int - 0 == success, else error                              */
    193       1.1  christos /* Parameters:  None                                                        */
    194       1.1  christos /*                                                                          */
    195       1.1  christos /* A null-op function that exists as a placeholder so that the flow in      */
    196       1.1  christos /* other functions is obvious.                                              */
    197       1.1  christos /* ------------------------------------------------------------------------ */
    198       1.1  christos int
    199       1.2  christos ipf_auth_main_unload(void)
    200       1.1  christos {
    201       1.1  christos 	return 0;
    202       1.1  christos }
    203       1.1  christos 
    204       1.1  christos 
    205       1.1  christos /* ------------------------------------------------------------------------ */
    206       1.1  christos /* Function:    ipf_auth_soft_create                                        */
    207       1.1  christos /* Returns:     int - NULL = failure, else success                          */
    208       1.1  christos /* Parameters:  softc(I) - pointer to soft context data                     */
    209       1.1  christos /*                                                                          */
    210       1.1  christos /* Create a structre to store all of the run-time data for packet auth in   */
    211       1.1  christos /* and initialise some fields to their defaults.                            */
    212       1.1  christos /* ------------------------------------------------------------------------ */
    213       1.1  christos void *
    214       1.2  christos ipf_auth_soft_create(ipf_main_softc_t *softc)
    215       1.1  christos {
    216       1.1  christos 	ipf_auth_softc_t *softa;
    217       1.1  christos 
    218       1.1  christos 	KMALLOC(softa, ipf_auth_softc_t *);
    219       1.1  christos 	if (softa == NULL)
    220       1.1  christos 		return NULL;
    221       1.1  christos 
    222       1.1  christos 	bzero((char *)softa, sizeof(*softa));
    223       1.1  christos 
    224       1.1  christos 	softa->ipf_auth_size = FR_NUMAUTH;
    225       1.1  christos 	softa->ipf_auth_defaultage = 600;
    226       1.1  christos 
    227       1.1  christos 	RWLOCK_INIT(&softa->ipf_authlk, "ipf IP User-Auth rwlock");
    228       1.1  christos 	MUTEX_INIT(&softa->ipf_auth_mx, "ipf auth log mutex");
    229       1.1  christos #if SOLARIS && defined(_KERNEL)
    230       1.1  christos 	cv_init(&softa->ipf_auth_wait, "ipf auth condvar", CV_DRIVER, NULL);
    231       1.1  christos #endif
    232       1.1  christos 
    233       1.1  christos 	return softa;
    234       1.1  christos }
    235       1.1  christos 
    236       1.1  christos /* ------------------------------------------------------------------------ */
    237       1.1  christos /* Function:    ipf_auth_soft_init                                          */
    238       1.1  christos /* Returns:     int - 0 == success, else error                              */
    239       1.1  christos /* Parameters:  softc(I) - pointer to soft context data                     */
    240       1.1  christos /*              arg(I)   - opaque pointer to auth context data              */
    241       1.1  christos /*                                                                          */
    242       1.1  christos /* Allocate memory and initialise data structures used in handling auth     */
    243       1.1  christos /* rules.                                                                   */
    244       1.1  christos /* ------------------------------------------------------------------------ */
    245       1.1  christos int
    246       1.2  christos ipf_auth_soft_init(ipf_main_softc_t *softc, void *arg)
    247       1.1  christos {
    248       1.1  christos 	ipf_auth_softc_t *softa = arg;
    249       1.1  christos 
    250       1.1  christos 	KMALLOCS(softa->ipf_auth, frauth_t *,
    251       1.1  christos 		 softa->ipf_auth_size * sizeof(*softa->ipf_auth));
    252       1.1  christos 	if (softa->ipf_auth == NULL)
    253       1.1  christos 		return -1;
    254       1.1  christos 	bzero((char *)softa->ipf_auth,
    255       1.1  christos 	      softa->ipf_auth_size * sizeof(*softa->ipf_auth));
    256       1.1  christos 
    257       1.1  christos 	KMALLOCS(softa->ipf_auth_pkts, mb_t **,
    258       1.1  christos 		 softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
    259       1.1  christos 	if (softa->ipf_auth_pkts == NULL)
    260       1.1  christos 		return -2;
    261       1.1  christos 	bzero((char *)softa->ipf_auth_pkts,
    262       1.1  christos 	      softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
    263       1.1  christos 
    264       1.1  christos #if defined(linux) && defined(_KERNEL)
    265       1.1  christos 	init_waitqueue_head(&softa->ipf_auth_next_linux);
    266       1.1  christos #endif
    267       1.1  christos 
    268       1.1  christos 	return 0;
    269       1.1  christos }
    270       1.1  christos 
    271       1.1  christos 
    272       1.1  christos /* ------------------------------------------------------------------------ */
    273       1.1  christos /* Function:    ipf_auth_soft_fini                                          */
    274       1.1  christos /* Returns:     int - 0 == success, else error                              */
    275       1.1  christos /* Parameters:  softc(I) - pointer to soft context data                     */
    276       1.1  christos /*              arg(I)   - opaque pointer to auth context data              */
    277       1.1  christos /*                                                                          */
    278       1.1  christos /* Free all network buffer memory used to keep saved packets that have been */
    279       1.1  christos /* connectedd to the soft soft context structure *but* do not free that: it */
    280       1.1  christos /* is free'd by _destroy().                                                 */
    281       1.1  christos /* ------------------------------------------------------------------------ */
    282       1.1  christos int
    283       1.2  christos ipf_auth_soft_fini(ipf_main_softc_t *softc, void *arg)
    284       1.1  christos {
    285       1.1  christos 	ipf_auth_softc_t *softa = arg;
    286       1.1  christos 	frauthent_t *fae, **faep;
    287       1.1  christos 	frentry_t *fr, **frp;
    288       1.1  christos 	mb_t *m;
    289       1.1  christos 	int i;
    290       1.1  christos 
    291       1.1  christos 	if (softa->ipf_auth != NULL) {
    292       1.1  christos 		KFREES(softa->ipf_auth,
    293       1.1  christos 		       softa->ipf_auth_size * sizeof(*softa->ipf_auth));
    294       1.1  christos 		softa->ipf_auth = NULL;
    295       1.1  christos 	}
    296       1.1  christos 
    297       1.1  christos 	if (softa->ipf_auth_pkts != NULL) {
    298       1.1  christos 		for (i = 0; i < softa->ipf_auth_size; i++) {
    299       1.1  christos 			m = softa->ipf_auth_pkts[i];
    300       1.1  christos 			if (m != NULL) {
    301       1.1  christos 				FREE_MB_T(m);
    302       1.1  christos 				softa->ipf_auth_pkts[i] = NULL;
    303       1.1  christos 			}
    304       1.1  christos 		}
    305       1.1  christos 		KFREES(softa->ipf_auth_pkts,
    306       1.1  christos 		       softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
    307       1.1  christos 		softa->ipf_auth_pkts = NULL;
    308       1.1  christos 	}
    309       1.1  christos 
    310       1.1  christos 	faep = &softa->ipf_auth_entries;
    311       1.1  christos 	while ((fae = *faep) != NULL) {
    312       1.1  christos 		*faep = fae->fae_next;
    313       1.1  christos 		KFREE(fae);
    314       1.1  christos 	}
    315       1.1  christos 	softa->ipf_auth_ip = NULL;
    316       1.1  christos 
    317       1.1  christos 	if (softa->ipf_auth_rules != NULL) {
    318       1.1  christos 		for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
    319       1.1  christos 			if (fr->fr_ref == 1) {
    320       1.1  christos 				*frp = fr->fr_next;
    321       1.1  christos 				MUTEX_DESTROY(&fr->fr_lock);
    322       1.1  christos 				KFREE(fr);
    323       1.1  christos 			} else
    324       1.1  christos 				frp = &fr->fr_next;
    325       1.1  christos 		}
    326       1.1  christos 	}
    327       1.1  christos 
    328       1.1  christos 	return 0;
    329       1.1  christos }
    330       1.1  christos 
    331       1.1  christos 
    332       1.1  christos /* ------------------------------------------------------------------------ */
    333       1.1  christos /* Function:    ipf_auth_soft_destroy                                       */
    334       1.1  christos /* Returns:     void                                                        */
    335       1.1  christos /* Parameters:  softc(I) - pointer to soft context data                     */
    336       1.1  christos /*              arg(I)   - opaque pointer to auth context data              */
    337       1.1  christos /*                                                                          */
    338       1.1  christos /* Undo what was done in _create() - i.e. free the soft context data.       */
    339       1.1  christos /* ------------------------------------------------------------------------ */
    340       1.1  christos void
    341       1.2  christos ipf_auth_soft_destroy(ipf_main_softc_t *softc, void *arg)
    342       1.1  christos {
    343       1.1  christos 	ipf_auth_softc_t *softa = arg;
    344       1.1  christos 
    345       1.1  christos # if SOLARIS && defined(_KERNEL)
    346       1.1  christos 	cv_destroy(&softa->ipf_auth_wait);
    347       1.1  christos # endif
    348       1.1  christos 	MUTEX_DESTROY(&softa->ipf_auth_mx);
    349       1.1  christos 	RW_DESTROY(&softa->ipf_authlk);
    350       1.1  christos 
    351       1.1  christos 	KFREE(softa);
    352       1.1  christos }
    353       1.1  christos 
    354       1.1  christos 
    355       1.1  christos /* ------------------------------------------------------------------------ */
    356       1.1  christos /* Function:    ipf_auth_setlock                                            */
    357       1.1  christos /* Returns:     void                                                        */
    358       1.1  christos /* Paramters:   arg(I) - pointer to soft context data                       */
    359       1.1  christos /*              tmp(I) - value to assign to auth lock                       */
    360       1.1  christos /*                                                                          */
    361       1.1  christos /* ------------------------------------------------------------------------ */
    362       1.1  christos void
    363       1.2  christos ipf_auth_setlock(void *arg, int tmp)
    364       1.1  christos {
    365       1.1  christos 	ipf_auth_softc_t *softa = arg;
    366       1.1  christos 
    367       1.1  christos 	softa->ipf_auth_lock = tmp;
    368       1.1  christos }
    369       1.1  christos 
    370       1.1  christos 
    371       1.1  christos /* ------------------------------------------------------------------------ */
    372       1.1  christos /* Function:    ipf_auth_check                                              */
    373       1.1  christos /* Returns:     frentry_t* - pointer to ipf rule if match found, else NULL  */
    374       1.1  christos /* Parameters:  fin(I)   - pointer to ipftoken structure                    */
    375       1.1  christos /*              passp(I) - pointer to ipfgeniter structure                  */
    376       1.1  christos /*                                                                          */
    377       1.1  christos /* Check if a packet has authorization.  If the packet is found to match an */
    378       1.1  christos /* authorization result and that would result in a feedback loop (i.e. it   */
    379       1.1  christos /* will end up returning FR_AUTH) then return FR_BLOCK instead.             */
    380       1.1  christos /* ------------------------------------------------------------------------ */
    381       1.1  christos frentry_t *
    382       1.2  christos ipf_auth_check(fr_info_t *fin, u_32_t *passp)
    383       1.1  christos {
    384       1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    385       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
    386       1.1  christos 	frentry_t *fr;
    387       1.1  christos 	frauth_t *fra;
    388       1.1  christos 	u_32_t pass;
    389       1.1  christos 	u_short id;
    390       1.1  christos 	ip_t *ip;
    391       1.1  christos 	int i;
    392       1.1  christos 
    393       1.1  christos 	if (softa->ipf_auth_lock || !softa->ipf_auth_used)
    394       1.1  christos 		return NULL;
    395       1.1  christos 
    396       1.1  christos 	ip = fin->fin_ip;
    397       1.1  christos 	id = ip->ip_id;
    398       1.1  christos 
    399       1.1  christos 	READ_ENTER(&softa->ipf_authlk);
    400       1.1  christos 	for (i = softa->ipf_auth_start; i != softa->ipf_auth_end; ) {
    401       1.1  christos 		/*
    402       1.1  christos 		 * index becomes -2 only after an SIOCAUTHW.  Check this in
    403       1.1  christos 		 * case the same packet gets sent again and it hasn't yet been
    404       1.1  christos 		 * auth'd.
    405       1.1  christos 		 */
    406       1.1  christos 		fra = softa->ipf_auth + i;
    407       1.1  christos 		if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) &&
    408       1.1  christos 		    !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) {
    409       1.1  christos 			/*
    410       1.1  christos 			 * Avoid feedback loop.
    411       1.1  christos 			 */
    412       1.1  christos 			if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) {
    413       1.1  christos 				pass = FR_BLOCK;
    414       1.1  christos 				fin->fin_reason = FRB_AUTHFEEDBACK;
    415       1.1  christos 			}
    416       1.1  christos 			/*
    417       1.1  christos 			 * Create a dummy rule for the stateful checking to
    418       1.1  christos 			 * use and return.  Zero out any values we don't
    419       1.1  christos 			 * trust from userland!
    420       1.1  christos 			 */
    421       1.1  christos 			if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) &&
    422       1.1  christos 			     (fin->fin_flx & FI_FRAG))) {
    423       1.1  christos 				KMALLOC(fr, frentry_t *);
    424       1.1  christos 				if (fr) {
    425       1.1  christos 					bcopy((char *)fra->fra_info.fin_fr,
    426       1.1  christos 					      (char *)fr, sizeof(*fr));
    427       1.1  christos 					fr->fr_grp = NULL;
    428       1.1  christos 					fr->fr_ifa = fin->fin_ifp;
    429       1.1  christos 					fr->fr_func = NULL;
    430       1.1  christos 					fr->fr_ref = 1;
    431       1.1  christos 					fr->fr_flags = pass;
    432       1.1  christos 					fr->fr_ifas[1] = NULL;
    433       1.1  christos 					fr->fr_ifas[2] = NULL;
    434       1.1  christos 					fr->fr_ifas[3] = NULL;
    435       1.1  christos 					MUTEX_INIT(&fr->fr_lock,
    436       1.1  christos 						   "ipf auth rule");
    437       1.1  christos 				}
    438       1.1  christos 			} else
    439       1.1  christos 				fr = fra->fra_info.fin_fr;
    440       1.1  christos 			fin->fin_fr = fr;
    441       1.1  christos 			fin->fin_flx |= fra->fra_flx;
    442       1.1  christos 			RWLOCK_EXIT(&softa->ipf_authlk);
    443       1.1  christos 
    444       1.1  christos 			WRITE_ENTER(&softa->ipf_authlk);
    445       1.1  christos 			/*
    446       1.1  christos 			 * ipf_auth_rules is populated with the rules malloc'd
    447       1.1  christos 			 * above and only those.
    448       1.1  christos 			 */
    449       1.1  christos 			if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
    450       1.1  christos 				fr->fr_next = softa->ipf_auth_rules;
    451       1.1  christos 				softa->ipf_auth_rules = fr;
    452       1.1  christos 			}
    453       1.1  christos 			softa->ipf_auth_stats.fas_hits++;
    454       1.1  christos 			fra->fra_index = -1;
    455       1.1  christos 			softa->ipf_auth_used--;
    456       1.1  christos 			softa->ipf_auth_replies--;
    457       1.1  christos 			if (i == softa->ipf_auth_start) {
    458       1.1  christos 				while (fra->fra_index == -1) {
    459       1.1  christos 					i++;
    460       1.1  christos 					fra++;
    461       1.1  christos 					if (i == softa->ipf_auth_size) {
    462       1.1  christos 						i = 0;
    463       1.1  christos 						fra = softa->ipf_auth;
    464       1.1  christos 					}
    465       1.1  christos 					softa->ipf_auth_start = i;
    466       1.1  christos 					if (i == softa->ipf_auth_end)
    467       1.1  christos 						break;
    468       1.1  christos 				}
    469       1.1  christos 				if (softa->ipf_auth_start ==
    470       1.1  christos 				    softa->ipf_auth_end) {
    471       1.1  christos 					softa->ipf_auth_next = 0;
    472       1.1  christos 					softa->ipf_auth_start = 0;
    473       1.1  christos 					softa->ipf_auth_end = 0;
    474       1.1  christos 				}
    475       1.1  christos 			}
    476       1.1  christos 			RWLOCK_EXIT(&softa->ipf_authlk);
    477       1.1  christos 			if (passp != NULL)
    478       1.1  christos 				*passp = pass;
    479       1.1  christos 			softa->ipf_auth_stats.fas_hits++;
    480       1.1  christos 			return fr;
    481       1.1  christos 		}
    482       1.1  christos 		i++;
    483       1.1  christos 		if (i == softa->ipf_auth_size)
    484       1.1  christos 			i = 0;
    485       1.1  christos 	}
    486       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
    487       1.1  christos 	softa->ipf_auth_stats.fas_miss++;
    488       1.1  christos 	return NULL;
    489       1.1  christos }
    490       1.1  christos 
    491       1.1  christos 
    492       1.1  christos /* ------------------------------------------------------------------------ */
    493       1.1  christos /* Function:    ipf_auth_new                                                */
    494       1.1  christos /* Returns:     int - 1 == success, 0 = did not put packet on auth queue    */
    495       1.1  christos /* Parameters:  m(I)   - pointer to mb_t with packet in it                  */
    496       1.1  christos /*              fin(I) - pointer to packet information                      */
    497       1.1  christos /*                                                                          */
    498       1.1  christos /* Check if we have room in the auth array to hold details for another      */
    499       1.1  christos /* packet. If we do, store it and wake up any user programs which are       */
    500       1.1  christos /* waiting to hear about these events.                                      */
    501       1.1  christos /* ------------------------------------------------------------------------ */
    502       1.1  christos int
    503       1.2  christos ipf_auth_new(mb_t *m, fr_info_t *fin)
    504       1.1  christos {
    505       1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    506       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
    507       1.1  christos #if defined(_KERNEL) && defined(MENTAT)
    508       1.1  christos 	qpktinfo_t *qpi = fin->fin_qpi;
    509       1.1  christos #endif
    510       1.1  christos 	frauth_t *fra;
    511       1.1  christos #if !defined(sparc) && !defined(m68k)
    512       1.1  christos 	ip_t *ip;
    513       1.1  christos #endif
    514       1.1  christos 	int i;
    515       1.1  christos 
    516       1.1  christos 	if (softa->ipf_auth_lock)
    517       1.1  christos 		return 0;
    518       1.1  christos 
    519       1.1  christos 	WRITE_ENTER(&softa->ipf_authlk);
    520       1.1  christos 	if (((softa->ipf_auth_end + 1) % softa->ipf_auth_size) ==
    521       1.1  christos 	    softa->ipf_auth_start) {
    522       1.1  christos 		softa->ipf_auth_stats.fas_nospace++;
    523       1.1  christos 		RWLOCK_EXIT(&softa->ipf_authlk);
    524       1.1  christos 		return 0;
    525       1.1  christos 	}
    526       1.1  christos 
    527       1.1  christos 	softa->ipf_auth_stats.fas_added++;
    528       1.1  christos 	softa->ipf_auth_used++;
    529       1.1  christos 	i = softa->ipf_auth_end++;
    530       1.1  christos 	if (softa->ipf_auth_end == softa->ipf_auth_size)
    531       1.1  christos 		softa->ipf_auth_end = 0;
    532       1.1  christos 
    533       1.1  christos 	fra = softa->ipf_auth + i;
    534       1.1  christos 	fra->fra_index = i;
    535       1.1  christos 	if (fin->fin_fr != NULL)
    536       1.1  christos 		fra->fra_pass = fin->fin_fr->fr_flags;
    537       1.1  christos 	else
    538       1.1  christos 		fra->fra_pass = 0;
    539       1.1  christos 	fra->fra_age = softa->ipf_auth_defaultage;
    540       1.1  christos 	bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
    541       1.1  christos 	fra->fra_flx = fra->fra_info.fin_flx & (FI_STATE|FI_NATED);
    542       1.1  christos 	fra->fra_info.fin_flx &= ~(FI_STATE|FI_NATED);
    543       1.1  christos #if !defined(sparc) && !defined(m68k)
    544       1.1  christos 	/*
    545       1.1  christos 	 * No need to copyback here as we want to undo the changes, not keep
    546       1.1  christos 	 * them.
    547       1.1  christos 	 */
    548       1.1  christos 	ip = fin->fin_ip;
    549       1.1  christos # if defined(MENTAT) && defined(_KERNEL)
    550       1.1  christos 	if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4))
    551       1.1  christos # endif
    552       1.1  christos 	{
    553       1.1  christos 		register u_short bo;
    554       1.1  christos 
    555       1.1  christos 		bo = ip->ip_len;
    556       1.1  christos 		ip->ip_len = htons(bo);
    557       1.1  christos 		bo = ip->ip_off;
    558       1.1  christos 		ip->ip_off = htons(bo);
    559       1.1  christos 	}
    560       1.1  christos #endif
    561       1.1  christos #if SOLARIS && defined(_KERNEL)
    562       1.1  christos 	COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname);
    563       1.1  christos 	m->b_rptr -= qpi->qpi_off;
    564       1.1  christos 	fra->fra_q = qpi->qpi_q;	/* The queue can disappear! */
    565       1.1  christos 	fra->fra_m = *fin->fin_mp;
    566       1.1  christos 	fra->fra_info.fin_mp = &fra->fra_m;
    567       1.1  christos 	softa->ipf_auth_pkts[i] = *(mblk_t **)fin->fin_mp;
    568       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
    569       1.1  christos 	cv_signal(&softa->ipf_auth_wait);
    570       1.1  christos 	pollwakeup(&softc->ipf_poll_head[IPL_LOGAUTH], POLLIN|POLLRDNORM);
    571       1.1  christos #else
    572       1.1  christos 	softa->ipf_auth_pkts[i] = m;
    573       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
    574       1.1  christos 	WAKEUP(&softa->ipf_auth_next, 0);
    575       1.1  christos #endif
    576       1.1  christos 	return 1;
    577       1.1  christos }
    578       1.1  christos 
    579       1.1  christos 
    580       1.1  christos /* ------------------------------------------------------------------------ */
    581       1.1  christos /* Function:    ipf_auth_ioctl                                              */
    582       1.1  christos /* Returns:     int - 0 == success, else error                              */
    583       1.1  christos /* Parameters:  data(IO) - pointer to ioctl data                            */
    584       1.1  christos /*              cmd(I)   - ioctl command                                    */
    585       1.1  christos /*              mode(I)  - mode flags associated with open descriptor       */
    586       1.1  christos /*              uid(I)   - uid associatd with application making the call   */
    587       1.1  christos /*              ctx(I)   - pointer for context                              */
    588       1.1  christos /*                                                                          */
    589       1.1  christos /* This function handles all of the ioctls recognised by the auth component */
    590       1.1  christos /* in IPFilter - ie ioctls called on an open fd for /dev/ipf_auth           */
    591       1.1  christos /* ------------------------------------------------------------------------ */
    592       1.1  christos int
    593       1.2  christos ipf_auth_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode,
    594       1.2  christos     int uid, void *ctx)
    595       1.1  christos {
    596       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
    597       1.1  christos 	int error = 0, i;
    598       1.1  christos 	SPL_INT(s);
    599       1.1  christos 
    600       1.1  christos 	switch (cmd)
    601       1.1  christos 	{
    602       1.1  christos 	case SIOCGENITER :
    603       1.1  christos 	    {
    604       1.1  christos 		ipftoken_t *token;
    605       1.1  christos 		ipfgeniter_t iter;
    606       1.1  christos 		ipfobj_t obj;
    607       1.1  christos 
    608       1.1  christos 		error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
    609       1.1  christos 		if (error != 0)
    610       1.1  christos 			break;
    611       1.1  christos 
    612       1.1  christos 		SPL_SCHED(s);
    613       1.1  christos 		token = ipf_token_find(softc, IPFGENITER_AUTH, uid, ctx);
    614       1.1  christos 		if (token != NULL)
    615       1.1  christos 			error = ipf_auth_geniter(softc, token, &iter, &obj);
    616       1.1  christos 		else {
    617       1.1  christos 			WRITE_ENTER(&softc->ipf_tokens);
    618       1.3   darrenr 			ipf_token_deref(softc, token);
    619       1.1  christos 			RWLOCK_EXIT(&softc->ipf_tokens);
    620       1.1  christos 			IPFERROR(10001);
    621       1.1  christos 			error = ESRCH;
    622       1.1  christos 		}
    623       1.1  christos 		SPL_X(s);
    624       1.1  christos 
    625       1.1  christos 		break;
    626       1.1  christos 	    }
    627       1.1  christos 
    628       1.1  christos 	case SIOCADAFR :
    629       1.1  christos 	case SIOCRMAFR :
    630       1.1  christos 		if (!(mode & FWRITE)) {
    631       1.1  christos 			IPFERROR(10002);
    632       1.1  christos 			error = EPERM;
    633       1.1  christos 		} else
    634       1.1  christos 			error = frrequest(softc, IPL_LOGAUTH, cmd, data,
    635       1.1  christos 					  softc->ipf_active, 1);
    636       1.1  christos 		break;
    637       1.1  christos 
    638       1.1  christos 	case SIOCSTLCK :
    639       1.1  christos 		if (!(mode & FWRITE)) {
    640       1.1  christos 			IPFERROR(10003);
    641       1.1  christos 			error = EPERM;
    642       1.1  christos 		} else {
    643       1.1  christos 			error = ipf_lock(data, &softa->ipf_auth_lock);
    644       1.1  christos 		}
    645       1.1  christos 		break;
    646       1.1  christos 
    647       1.1  christos 	case SIOCATHST:
    648       1.1  christos 		softa->ipf_auth_stats.fas_faelist = softa->ipf_auth_entries;
    649       1.1  christos 		error = ipf_outobj(softc, data, &softa->ipf_auth_stats,
    650       1.1  christos 				   IPFOBJ_AUTHSTAT);
    651       1.1  christos 		break;
    652       1.1  christos 
    653       1.1  christos 	case SIOCIPFFL:
    654       1.1  christos 		SPL_NET(s);
    655       1.1  christos 		WRITE_ENTER(&softa->ipf_authlk);
    656       1.1  christos 		i = ipf_auth_flush(softa);
    657       1.1  christos 		RWLOCK_EXIT(&softa->ipf_authlk);
    658       1.1  christos 		SPL_X(s);
    659       1.1  christos 		error = BCOPYOUT(&i, data, sizeof(i));
    660       1.1  christos 		if (error != 0) {
    661       1.1  christos 			IPFERROR(10004);
    662       1.1  christos 			error = EFAULT;
    663       1.1  christos 		}
    664       1.1  christos 		break;
    665       1.1  christos 
    666       1.1  christos 	case SIOCAUTHW:
    667       1.1  christos 		error = ipf_auth_wait(softc, softa, data);
    668       1.1  christos 		break;
    669       1.1  christos 
    670       1.1  christos 	case SIOCAUTHR:
    671       1.1  christos 		error = ipf_auth_reply(softc, softa, data);
    672       1.1  christos 		break;
    673       1.1  christos 
    674       1.1  christos 	default :
    675       1.1  christos 		IPFERROR(10005);
    676       1.1  christos 		error = EINVAL;
    677       1.1  christos 		break;
    678       1.1  christos 	}
    679       1.1  christos 	return error;
    680       1.1  christos }
    681       1.1  christos 
    682       1.1  christos 
    683       1.1  christos /* ------------------------------------------------------------------------ */
    684       1.1  christos /* Function:    ipf_auth_expire                                             */
    685       1.1  christos /* Returns:     None                                                        */
    686       1.1  christos /* Parameters:  None                                                        */
    687       1.1  christos /*                                                                          */
    688       1.1  christos /* Slowly expire held auth records.  Timeouts are set in expectation of     */
    689       1.1  christos /* this being called twice per second.                                      */
    690       1.1  christos /* ------------------------------------------------------------------------ */
    691       1.1  christos void
    692       1.2  christos ipf_auth_expire(ipf_main_softc_t *softc)
    693       1.1  christos {
    694       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
    695       1.1  christos 	frauthent_t *fae, **faep;
    696       1.1  christos 	frentry_t *fr, **frp;
    697       1.1  christos 	frauth_t *fra;
    698       1.1  christos 	mb_t *m;
    699       1.1  christos 	int i;
    700       1.1  christos 	SPL_INT(s);
    701       1.1  christos 
    702       1.1  christos 	if (softa->ipf_auth_lock)
    703       1.1  christos 		return;
    704       1.1  christos 	SPL_NET(s);
    705       1.1  christos 	WRITE_ENTER(&softa->ipf_authlk);
    706       1.1  christos 	for (i = 0, fra = softa->ipf_auth; i < softa->ipf_auth_size;
    707       1.1  christos 	     i++, fra++) {
    708       1.1  christos 		fra->fra_age--;
    709       1.1  christos 		if ((fra->fra_age == 0) &&
    710       1.1  christos 		    (softa->ipf_auth[i].fra_index != -1)) {
    711       1.1  christos 			if ((m = softa->ipf_auth_pkts[i]) != NULL) {
    712       1.1  christos 				FREE_MB_T(m);
    713       1.1  christos 				softa->ipf_auth_pkts[i] = NULL;
    714       1.1  christos 			} else if (softa->ipf_auth[i].fra_index == -2) {
    715       1.1  christos 				softa->ipf_auth_replies--;
    716       1.1  christos 			}
    717       1.1  christos 			softa->ipf_auth[i].fra_index = -1;
    718       1.1  christos 			softa->ipf_auth_stats.fas_expire++;
    719       1.1  christos 			softa->ipf_auth_used--;
    720       1.1  christos 		}
    721       1.1  christos 	}
    722       1.1  christos 
    723       1.1  christos 	/*
    724       1.1  christos 	 * Expire pre-auth rules
    725       1.1  christos 	 */
    726       1.1  christos 	for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) {
    727       1.1  christos 		fae->fae_age--;
    728       1.1  christos 		if (fae->fae_age == 0) {
    729       1.1  christos 			ipf_auth_deref(&fae);
    730       1.1  christos 			softa->ipf_auth_stats.fas_expire++;
    731       1.1  christos 		} else
    732       1.1  christos 			faep = &fae->fae_next;
    733       1.1  christos 	}
    734       1.1  christos 	if (softa->ipf_auth_entries != NULL)
    735       1.1  christos 		softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
    736       1.1  christos 	else
    737       1.1  christos 		softa->ipf_auth_ip = NULL;
    738       1.1  christos 
    739       1.1  christos 	for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
    740       1.1  christos 		if (fr->fr_ref == 1) {
    741       1.1  christos 			*frp = fr->fr_next;
    742       1.1  christos 			MUTEX_DESTROY(&fr->fr_lock);
    743       1.1  christos 			KFREE(fr);
    744       1.1  christos 		} else
    745       1.1  christos 			frp = &fr->fr_next;
    746       1.1  christos 	}
    747       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
    748       1.1  christos 	SPL_X(s);
    749       1.1  christos }
    750       1.1  christos 
    751       1.1  christos 
    752       1.1  christos /* ------------------------------------------------------------------------ */
    753       1.1  christos /* Function:    ipf_auth_precmd                                             */
    754       1.1  christos /* Returns:     int - 0 == success, else error                              */
    755       1.1  christos /* Parameters:  cmd(I)  - ioctl command for rule                            */
    756       1.1  christos /*              fr(I)   - pointer to ipf rule                               */
    757       1.1  christos /*              fptr(I) - pointer to caller's 'fr'                          */
    758       1.1  christos /*                                                                          */
    759       1.1  christos /* ------------------------------------------------------------------------ */
    760       1.1  christos int
    761       1.2  christos ipf_auth_precmd(ipf_main_softc_t *softc, ioctlcmd_t cmd, frentry_t *fr,
    762       1.2  christos     frentry_t **frptr)
    763       1.1  christos {
    764       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
    765       1.1  christos 	frauthent_t *fae, **faep;
    766       1.1  christos 	int error = 0;
    767       1.1  christos 	SPL_INT(s);
    768       1.1  christos 
    769       1.1  christos 	if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) {
    770       1.1  christos 		IPFERROR(10006);
    771       1.1  christos 		return EIO;
    772       1.1  christos 	}
    773       1.1  christos 
    774       1.1  christos 	for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) {
    775       1.1  christos 		if (&fae->fae_fr == fr)
    776       1.1  christos 			break;
    777       1.1  christos 		else
    778       1.1  christos 			faep = &fae->fae_next;
    779       1.1  christos 	}
    780       1.1  christos 
    781       1.1  christos 	if (cmd == (ioctlcmd_t)SIOCRMAFR) {
    782       1.1  christos 		if (fr == NULL || frptr == NULL) {
    783       1.1  christos 			IPFERROR(10007);
    784       1.1  christos 			error = EINVAL;
    785       1.1  christos 
    786       1.1  christos 		} else if (fae == NULL) {
    787       1.1  christos 			IPFERROR(10008);
    788       1.1  christos 			error = ESRCH;
    789       1.1  christos 
    790       1.1  christos 		} else {
    791       1.1  christos 			SPL_NET(s);
    792       1.1  christos 			WRITE_ENTER(&softa->ipf_authlk);
    793       1.1  christos 			*faep = fae->fae_next;
    794       1.1  christos 			if (softa->ipf_auth_ip == &fae->fae_fr)
    795       1.1  christos 				softa->ipf_auth_ip = softa->ipf_auth_entries ?
    796       1.1  christos 				    &softa->ipf_auth_entries->fae_fr : NULL;
    797       1.1  christos 			RWLOCK_EXIT(&softa->ipf_authlk);
    798       1.1  christos 			SPL_X(s);
    799       1.1  christos 
    800       1.1  christos 			KFREE(fae);
    801       1.1  christos 		}
    802       1.1  christos 	} else if (fr != NULL && frptr != NULL) {
    803       1.1  christos 		KMALLOC(fae, frauthent_t *);
    804       1.1  christos 		if (fae != NULL) {
    805       1.1  christos 			bcopy((char *)fr, (char *)&fae->fae_fr,
    806       1.1  christos 			      sizeof(*fr));
    807       1.1  christos 			SPL_NET(s);
    808       1.1  christos 			WRITE_ENTER(&softa->ipf_authlk);
    809       1.1  christos 			fae->fae_age = softa->ipf_auth_defaultage;
    810       1.1  christos 			fae->fae_fr.fr_hits = 0;
    811       1.1  christos 			fae->fae_fr.fr_next = *frptr;
    812       1.1  christos 			fae->fae_ref = 1;
    813       1.1  christos 			*frptr = &fae->fae_fr;
    814       1.1  christos 			fae->fae_next = *faep;
    815       1.1  christos 			*faep = fae;
    816       1.1  christos 			softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
    817       1.1  christos 			RWLOCK_EXIT(&softa->ipf_authlk);
    818       1.1  christos 			SPL_X(s);
    819       1.1  christos 		} else {
    820       1.1  christos 			IPFERROR(10009);
    821       1.1  christos 			error = ENOMEM;
    822       1.1  christos 		}
    823       1.1  christos 	} else {
    824       1.1  christos 		IPFERROR(10010);
    825       1.1  christos 		error = EINVAL;
    826       1.1  christos 	}
    827       1.1  christos 	return error;
    828       1.1  christos }
    829       1.1  christos 
    830       1.1  christos 
    831       1.1  christos /* ------------------------------------------------------------------------ */
    832       1.1  christos /* Function:    ipf_auth_flush                                              */
    833       1.1  christos /* Returns:     int - number of auth entries flushed                        */
    834       1.1  christos /* Parameters:  None                                                        */
    835       1.1  christos /* Locks:       WRITE(ipf_authlk)                                           */
    836       1.1  christos /*                                                                          */
    837       1.1  christos /* This function flushs the ipf_auth_pkts array of any packet data with     */
    838       1.1  christos /* references still there.                                                  */
    839       1.1  christos /* It is expected that the caller has already acquired the correct locks or */
    840       1.1  christos /* set the priority level correctly for this to block out other code paths  */
    841       1.1  christos /* into these data structures.                                              */
    842       1.1  christos /* ------------------------------------------------------------------------ */
    843       1.1  christos static int
    844       1.2  christos ipf_auth_flush(void *arg)
    845       1.1  christos {
    846       1.1  christos 	ipf_auth_softc_t *softa = arg;
    847       1.1  christos 	int i, num_flushed;
    848       1.1  christos 	mb_t *m;
    849       1.1  christos 
    850       1.1  christos 	if (softa->ipf_auth_lock)
    851       1.1  christos 		return -1;
    852       1.1  christos 
    853       1.1  christos 	num_flushed = 0;
    854       1.1  christos 
    855       1.1  christos 	for (i = 0 ; i < softa->ipf_auth_size; i++) {
    856       1.1  christos 		if (softa->ipf_auth[i].fra_index != -1) {
    857       1.1  christos 			m = softa->ipf_auth_pkts[i];
    858       1.1  christos 			if (m != NULL) {
    859       1.1  christos 				FREE_MB_T(m);
    860       1.1  christos 				softa->ipf_auth_pkts[i] = NULL;
    861       1.1  christos 			}
    862       1.1  christos 
    863       1.1  christos 			softa->ipf_auth[i].fra_index = -1;
    864       1.1  christos 			/* perhaps add & use a flush counter inst.*/
    865       1.1  christos 			softa->ipf_auth_stats.fas_expire++;
    866       1.1  christos 			num_flushed++;
    867       1.1  christos 		}
    868       1.1  christos 	}
    869       1.1  christos 
    870       1.1  christos 	softa->ipf_auth_start = 0;
    871       1.1  christos 	softa->ipf_auth_end = 0;
    872       1.1  christos 	softa->ipf_auth_next = 0;
    873       1.1  christos 	softa->ipf_auth_used = 0;
    874       1.1  christos 	softa->ipf_auth_replies = 0;
    875       1.1  christos 
    876       1.1  christos 	return num_flushed;
    877       1.1  christos }
    878       1.1  christos 
    879       1.1  christos 
    880       1.1  christos /* ------------------------------------------------------------------------ */
    881       1.1  christos /* Function:    ipf_auth_waiting                                            */
    882       1.1  christos /* Returns:     int - number of packets in the auth queue                   */
    883       1.1  christos /* Parameters:  None                                                        */
    884       1.1  christos /*                                                                          */
    885       1.1  christos /* Simple truth check to see if there are any packets waiting in the auth   */
    886       1.1  christos /* queue.                                                                   */
    887       1.1  christos /* ------------------------------------------------------------------------ */
    888       1.1  christos int
    889       1.2  christos ipf_auth_waiting(ipf_main_softc_t *softc)
    890       1.1  christos {
    891       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
    892       1.1  christos 
    893       1.1  christos 	return (softa->ipf_auth_used != 0);
    894       1.1  christos }
    895       1.1  christos 
    896       1.1  christos 
    897       1.1  christos /* ------------------------------------------------------------------------ */
    898       1.1  christos /* Function:    ipf_auth_geniter                                            */
    899       1.1  christos /* Returns:     int - 0 == success, else error                              */
    900       1.1  christos /* Parameters:  token(I) - pointer to ipftoken structure                    */
    901       1.1  christos /*              itp(I)   - pointer to ipfgeniter structure                  */
    902       1.1  christos /*              objp(I)  - pointer to ipf object destription                */
    903       1.1  christos /*                                                                          */
    904       1.1  christos /* Iterate through the list of entries in the auth queue list.              */
    905       1.1  christos /* objp is used here to get the location of where to do the copy out to.    */
    906       1.1  christos /* Stomping over various fields with new information will not harm anything */
    907       1.1  christos /* ------------------------------------------------------------------------ */
    908       1.1  christos static int
    909       1.2  christos ipf_auth_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp,
    910       1.2  christos     ipfobj_t *objp)
    911       1.1  christos {
    912       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
    913       1.1  christos 	frauthent_t *fae, *next, zero;
    914       1.1  christos 	int error;
    915       1.1  christos 
    916       1.1  christos 	if (itp->igi_data == NULL) {
    917       1.1  christos 		IPFERROR(10011);
    918       1.1  christos 		return EFAULT;
    919       1.1  christos 	}
    920       1.1  christos 
    921       1.1  christos 	if (itp->igi_type != IPFGENITER_AUTH) {
    922       1.1  christos 		IPFERROR(10012);
    923       1.1  christos 		return EINVAL;
    924       1.1  christos 	}
    925       1.1  christos 
    926       1.1  christos 	objp->ipfo_type = IPFOBJ_FRAUTH;
    927       1.1  christos 	objp->ipfo_ptr = itp->igi_data;
    928       1.1  christos 	objp->ipfo_size = sizeof(frauth_t);
    929       1.1  christos 
    930       1.1  christos 	READ_ENTER(&softa->ipf_authlk);
    931       1.1  christos 
    932       1.1  christos 	fae = token->ipt_data;
    933       1.1  christos 	if (fae == NULL) {
    934       1.1  christos 		next = softa->ipf_auth_entries;
    935       1.1  christos 	} else {
    936       1.1  christos 		next = fae->fae_next;
    937       1.1  christos 	}
    938       1.1  christos 
    939       1.1  christos 	/*
    940       1.1  christos 	 * If we found an auth entry to use, bump its reference count
    941       1.1  christos 	 * so that it can be used for is_next when we come back.
    942       1.1  christos 	 */
    943       1.1  christos 	if (next != NULL) {
    944       1.1  christos 		ATOMIC_INC(next->fae_ref);
    945       1.1  christos 		token->ipt_data = next;
    946       1.1  christos 	} else {
    947       1.1  christos 		bzero(&zero, sizeof(zero));
    948       1.1  christos 		next = &zero;
    949       1.1  christos 		token->ipt_data = NULL;
    950       1.1  christos 	}
    951       1.1  christos 
    952       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
    953       1.1  christos 
    954       1.1  christos 	error = ipf_outobjk(softc, objp, next);
    955       1.1  christos 	if (fae != NULL)
    956       1.1  christos 		ipf_auth_deref_unlocked(softa, &fae);
    957       1.1  christos 
    958       1.1  christos 	if (next->fae_next == NULL)
    959       1.1  christos 		ipf_token_mark_complete(token);
    960       1.1  christos 	return error;
    961       1.1  christos }
    962       1.1  christos 
    963       1.1  christos 
    964       1.1  christos /* ------------------------------------------------------------------------ */
    965       1.1  christos /* Function:    ipf_auth_deref_unlocked                                     */
    966       1.1  christos /* Returns:     None                                                        */
    967       1.1  christos /* Parameters:  faep(IO) - pointer to caller's frauthent_t pointer          */
    968       1.1  christos /*                                                                          */
    969       1.1  christos /* Wrapper for ipf_auth_deref for when a write lock on ipf_authlk is not    */
    970       1.1  christos /* held.                                                                    */
    971       1.1  christos /* ------------------------------------------------------------------------ */
    972       1.1  christos static void
    973       1.2  christos ipf_auth_deref_unlocked(ipf_auth_softc_t *softa, frauthent_t **faep)
    974       1.1  christos {
    975       1.1  christos 	WRITE_ENTER(&softa->ipf_authlk);
    976       1.1  christos 	ipf_auth_deref(faep);
    977       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
    978       1.1  christos }
    979       1.1  christos 
    980       1.1  christos 
    981       1.1  christos /* ------------------------------------------------------------------------ */
    982       1.1  christos /* Function:    ipf_auth_deref                                              */
    983       1.1  christos /* Returns:     None                                                        */
    984       1.1  christos /* Parameters:  faep(IO) - pointer to caller's frauthent_t pointer          */
    985       1.1  christos /* Locks:       WRITE(ipf_authlk)                                           */
    986       1.1  christos /*                                                                          */
    987       1.1  christos /* This function unconditionally sets the pointer in the caller to NULL,    */
    988       1.1  christos /* to make it clear that it should no longer use that pointer, and drops    */
    989       1.1  christos /* the reference count on the structure by 1.  If it reaches 0, free it up. */
    990       1.1  christos /* ------------------------------------------------------------------------ */
    991       1.1  christos static void
    992       1.2  christos ipf_auth_deref(frauthent_t **faep)
    993       1.1  christos {
    994       1.1  christos 	frauthent_t *fae;
    995       1.1  christos 
    996       1.1  christos 	fae = *faep;
    997       1.1  christos 	*faep = NULL;
    998       1.1  christos 
    999       1.1  christos 	fae->fae_ref--;
   1000       1.1  christos 	if (fae->fae_ref == 0) {
   1001       1.1  christos 		KFREE(fae);
   1002       1.1  christos 	}
   1003       1.1  christos }
   1004       1.1  christos 
   1005       1.1  christos 
   1006       1.1  christos /* ------------------------------------------------------------------------ */
   1007       1.1  christos /* Function:    ipf_auth_wait_pkt                                           */
   1008       1.1  christos /* Returns:     int - 0 == success, else error                              */
   1009       1.1  christos /* Parameters:  data(I) - pointer to data from ioctl call                   */
   1010       1.1  christos /*                                                                          */
   1011       1.1  christos /* This function is called when an application is waiting for a packet to   */
   1012       1.1  christos /* match an "auth" rule by issuing an SIOCAUTHW ioctl.  If there is already */
   1013       1.1  christos /* a packet waiting on the queue then we will return that _one_ immediately.*/
   1014       1.1  christos /* If there are no packets present in the queue (ipf_auth_pkts) then we go  */
   1015       1.1  christos /* to sleep.                                                                */
   1016       1.1  christos /* ------------------------------------------------------------------------ */
   1017       1.1  christos static int
   1018       1.2  christos ipf_auth_wait(ipf_main_softc_t *softc, ipf_auth_softc_t *softa, char *data)
   1019       1.1  christos {
   1020       1.1  christos 	frauth_t auth, *au = &auth;
   1021       1.1  christos 	int error, len, i;
   1022       1.1  christos 	mb_t *m;
   1023       1.1  christos 	char *t;
   1024       1.1  christos 	SPL_INT(s);
   1025       1.1  christos 
   1026       1.1  christos ipf_auth_ioctlloop:
   1027       1.1  christos 	error = ipf_inobj(softc, data, NULL, au, IPFOBJ_FRAUTH);
   1028       1.1  christos 	if (error != 0)
   1029       1.1  christos 		return error;
   1030       1.1  christos 
   1031       1.1  christos 	/*
   1032       1.1  christos 	 * XXX Locks are held below over calls to copyout...a better
   1033       1.1  christos 	 * solution needs to be found so this isn't necessary.  The situation
   1034       1.1  christos 	 * we are trying to guard against here is an error in the copyout
   1035       1.1  christos 	 * steps should not cause the packet to "disappear" from the queue.
   1036       1.1  christos 	 */
   1037       1.1  christos 	SPL_NET(s);
   1038       1.1  christos 	READ_ENTER(&softa->ipf_authlk);
   1039       1.1  christos 
   1040       1.1  christos 	/*
   1041       1.1  christos 	 * If ipf_auth_next is not equal to ipf_auth_end it will be because
   1042       1.1  christos 	 * there is a packet waiting to be delt with in the ipf_auth_pkts
   1043       1.1  christos 	 * array.  We copy as much of that out to user space as requested.
   1044       1.1  christos 	 */
   1045       1.1  christos 	if (softa->ipf_auth_used > 0) {
   1046       1.1  christos 		while (softa->ipf_auth_pkts[softa->ipf_auth_next] == NULL) {
   1047       1.1  christos 			softa->ipf_auth_next++;
   1048       1.1  christos 			if (softa->ipf_auth_next == softa->ipf_auth_size)
   1049       1.1  christos 				softa->ipf_auth_next = 0;
   1050       1.1  christos 		}
   1051       1.1  christos 
   1052       1.1  christos 		error = ipf_outobj(softc, data,
   1053       1.1  christos 				   &softa->ipf_auth[softa->ipf_auth_next],
   1054       1.1  christos 				   IPFOBJ_FRAUTH);
   1055       1.1  christos 		if (error != 0) {
   1056       1.1  christos 			RWLOCK_EXIT(&softa->ipf_authlk);
   1057       1.1  christos 			SPL_X(s);
   1058       1.1  christos 			return error;
   1059       1.1  christos 		}
   1060       1.1  christos 
   1061       1.1  christos 		if (auth.fra_len != 0 && auth.fra_buf != NULL) {
   1062       1.1  christos 			/*
   1063       1.1  christos 			 * Copy packet contents out to user space if
   1064       1.1  christos 			 * requested.  Bail on an error.
   1065       1.1  christos 			 */
   1066       1.1  christos 			m = softa->ipf_auth_pkts[softa->ipf_auth_next];
   1067       1.1  christos 			len = MSGDSIZE(m);
   1068       1.1  christos 			if (len > auth.fra_len)
   1069       1.1  christos 				len = auth.fra_len;
   1070       1.1  christos 			auth.fra_len = len;
   1071       1.1  christos 
   1072       1.1  christos 			for (t = auth.fra_buf; m && (len > 0); ) {
   1073       1.1  christos 				i = MIN(M_LEN(m), len);
   1074       1.1  christos 				error = copyoutptr(softc, MTOD(m, char *),
   1075       1.1  christos 						   &t, i);
   1076       1.1  christos 				len -= i;
   1077       1.1  christos 				t += i;
   1078       1.1  christos 				if (error != 0) {
   1079       1.1  christos 					RWLOCK_EXIT(&softa->ipf_authlk);
   1080       1.1  christos 					SPL_X(s);
   1081       1.1  christos 					return error;
   1082       1.1  christos 				}
   1083       1.1  christos 				m = m->m_next;
   1084       1.1  christos 			}
   1085       1.1  christos 		}
   1086       1.1  christos 		RWLOCK_EXIT(&softa->ipf_authlk);
   1087       1.1  christos 
   1088       1.1  christos 		SPL_NET(s);
   1089       1.1  christos 		WRITE_ENTER(&softa->ipf_authlk);
   1090       1.1  christos 		softa->ipf_auth_next++;
   1091       1.1  christos 		if (softa->ipf_auth_next == softa->ipf_auth_size)
   1092       1.1  christos 			softa->ipf_auth_next = 0;
   1093       1.1  christos 		RWLOCK_EXIT(&softa->ipf_authlk);
   1094       1.1  christos 		SPL_X(s);
   1095       1.1  christos 
   1096       1.1  christos 		return 0;
   1097       1.1  christos 	}
   1098       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
   1099       1.1  christos 	SPL_X(s);
   1100       1.1  christos 
   1101       1.1  christos 	MUTEX_ENTER(&softa->ipf_auth_mx);
   1102       1.1  christos #ifdef	_KERNEL
   1103       1.1  christos # if	SOLARIS
   1104       1.1  christos 	error = 0;
   1105       1.1  christos 	if (!cv_wait_sig(&softa->ipf_auth_wait, &softa->ipf_auth_mx.ipf_lk)) {
   1106       1.1  christos 		IPFERROR(10014);
   1107       1.1  christos 		error = EINTR;
   1108       1.1  christos 	}
   1109       1.1  christos # else /* SOLARIS */
   1110       1.1  christos #  ifdef __hpux
   1111       1.1  christos 	{
   1112       1.1  christos 	lock_t *l;
   1113       1.1  christos 
   1114       1.1  christos 	l = get_sleep_lock(&softa->ipf_auth_next);
   1115       1.1  christos 	error = sleep(&softa->ipf_auth_next, PZERO+1);
   1116       1.1  christos 	spinunlock(l);
   1117       1.1  christos 	}
   1118       1.1  christos #  else
   1119       1.1  christos #   ifdef __osf__
   1120       1.1  christos 	error = mpsleep(&softa->ipf_auth_next, PSUSP|PCATCH, "ipf_auth_next",
   1121       1.1  christos 			0, &softa->ipf_auth_mx, MS_LOCK_SIMPLE);
   1122       1.1  christos #   else
   1123       1.1  christos 	error = SLEEP(&softa->ipf_auth_next, "ipf_auth_next");
   1124       1.1  christos #   endif /* __osf__ */
   1125       1.1  christos #  endif /* __hpux */
   1126       1.1  christos # endif /* SOLARIS */
   1127       1.1  christos #endif
   1128       1.1  christos 	MUTEX_EXIT(&softa->ipf_auth_mx);
   1129       1.1  christos 	if (error == 0)
   1130       1.1  christos 		goto ipf_auth_ioctlloop;
   1131       1.1  christos 	return error;
   1132       1.1  christos }
   1133       1.1  christos 
   1134       1.1  christos 
   1135       1.1  christos /* ------------------------------------------------------------------------ */
   1136       1.1  christos /* Function:    ipf_auth_reply                                              */
   1137       1.1  christos /* Returns:     int - 0 == success, else error                              */
   1138       1.1  christos /* Parameters:  data(I) - pointer to data from ioctl call                   */
   1139       1.1  christos /*                                                                          */
   1140       1.1  christos /* This function is called by an application when it wants to return a      */
   1141       1.1  christos /* decision on a packet using the SIOCAUTHR ioctl.  This is after it has    */
   1142       1.1  christos /* received information using an SIOCAUTHW.  The decision returned in the   */
   1143       1.1  christos /* form of flags, the same as those used in each rule.                      */
   1144       1.1  christos /* ------------------------------------------------------------------------ */
   1145       1.1  christos static int
   1146       1.2  christos ipf_auth_reply(ipf_main_softc_t *softc, ipf_auth_softc_t *softa, char *data)
   1147       1.1  christos {
   1148       1.1  christos 	frauth_t auth, *au = &auth, *fra;
   1149       1.1  christos 	fr_info_t fin;
   1150       1.1  christos 	int error, i;
   1151       1.4  christos #ifdef _KERNEL
   1152       1.1  christos 	mb_t *m;
   1153       1.4  christos #endif
   1154       1.1  christos 	SPL_INT(s);
   1155       1.1  christos 
   1156       1.1  christos 	error = ipf_inobj(softc, data, NULL, &auth, IPFOBJ_FRAUTH);
   1157       1.1  christos 	if (error != 0)
   1158       1.1  christos 		return error;
   1159       1.1  christos 
   1160       1.1  christos 	SPL_NET(s);
   1161       1.1  christos 	WRITE_ENTER(&softa->ipf_authlk);
   1162       1.1  christos 
   1163       1.1  christos 	i = au->fra_index;
   1164       1.1  christos 	fra = softa->ipf_auth + i;
   1165       1.1  christos 	error = 0;
   1166       1.1  christos 
   1167       1.1  christos 	/*
   1168       1.1  christos 	 * Check the validity of the information being returned with two simple
   1169       1.1  christos 	 * checks.  First, the auth index value should be within the size of
   1170       1.1  christos 	 * the array and second the packet id being returned should also match.
   1171       1.1  christos 	 */
   1172       1.1  christos 	if ((i < 0) || (i >= softa->ipf_auth_size)) {
   1173       1.1  christos 		RWLOCK_EXIT(&softa->ipf_authlk);
   1174       1.1  christos 		SPL_X(s);
   1175       1.1  christos 		IPFERROR(10015);
   1176       1.1  christos 		return ESRCH;
   1177       1.1  christos 	}
   1178       1.1  christos 	if  (fra->fra_info.fin_id != au->fra_info.fin_id) {
   1179       1.1  christos 		RWLOCK_EXIT(&softa->ipf_authlk);
   1180       1.1  christos 		SPL_X(s);
   1181       1.1  christos 		IPFERROR(10019);
   1182       1.1  christos 		return ESRCH;
   1183       1.1  christos 	}
   1184       1.1  christos 
   1185       1.1  christos 	fra->fra_index = -2;
   1186       1.1  christos 	fra->fra_pass = au->fra_pass;
   1187       1.4  christos #ifdef	_KERNEL
   1188       1.4  christos 	m = softa->ipf_auth_pkts[i];
   1189       1.4  christos #endif
   1190       1.1  christos 	softa->ipf_auth_pkts[i] = NULL;
   1191       1.1  christos 	softa->ipf_auth_replies++;
   1192       1.1  christos 	bcopy(&fra->fra_info, &fin, sizeof(fin));
   1193       1.1  christos 
   1194       1.1  christos 	RWLOCK_EXIT(&softa->ipf_authlk);
   1195       1.1  christos 
   1196       1.1  christos 	/*
   1197       1.1  christos 	 * Re-insert the packet back into the packet stream flowing through
   1198       1.1  christos 	 * the kernel in a manner that will mean IPFilter sees the packet
   1199       1.1  christos 	 * again.  This is not the same as is done with fastroute,
   1200       1.1  christos 	 * deliberately, as we want to resume the normal packet processing
   1201       1.1  christos 	 * path for it.
   1202       1.1  christos 	 */
   1203       1.1  christos #ifdef	_KERNEL
   1204       1.1  christos 	if ((m != NULL) && (au->fra_info.fin_out != 0)) {
   1205       1.1  christos 		error = ipf_inject(&fin, m);
   1206       1.1  christos 		if (error != 0) {
   1207       1.1  christos 			IPFERROR(10016);
   1208       1.1  christos 			error = ENOBUFS;
   1209       1.1  christos 			softa->ipf_auth_stats.fas_sendfail++;
   1210       1.1  christos 		} else {
   1211       1.1  christos 			softa->ipf_auth_stats.fas_sendok++;
   1212       1.1  christos 		}
   1213       1.1  christos 	} else if (m) {
   1214       1.1  christos 		error = ipf_inject(&fin, m);
   1215       1.1  christos 		if (error != 0) {
   1216       1.1  christos 			IPFERROR(10017);
   1217       1.1  christos 			error = ENOBUFS;
   1218       1.1  christos 			softa->ipf_auth_stats.fas_quefail++;
   1219       1.1  christos 		} else {
   1220       1.1  christos 			softa->ipf_auth_stats.fas_queok++;
   1221       1.1  christos 		}
   1222       1.1  christos 	} else {
   1223       1.1  christos 		IPFERROR(10018);
   1224       1.1  christos 		error = EINVAL;
   1225       1.1  christos 	}
   1226       1.1  christos 
   1227       1.1  christos 	/*
   1228       1.1  christos 	 * If we experience an error which will result in the packet
   1229       1.1  christos 	 * not being processed, make sure we advance to the next one.
   1230       1.1  christos 	 */
   1231       1.1  christos 	if (error == ENOBUFS) {
   1232       1.1  christos 		WRITE_ENTER(&softa->ipf_authlk);
   1233       1.1  christos 		softa->ipf_auth_used--;
   1234       1.1  christos 		fra->fra_index = -1;
   1235       1.1  christos 		fra->fra_pass = 0;
   1236       1.1  christos 		if (i == softa->ipf_auth_start) {
   1237       1.1  christos 			while (fra->fra_index == -1) {
   1238       1.1  christos 				i++;
   1239       1.1  christos 				if (i == softa->ipf_auth_size)
   1240       1.1  christos 					i = 0;
   1241       1.1  christos 				softa->ipf_auth_start = i;
   1242       1.1  christos 				if (i == softa->ipf_auth_end)
   1243       1.1  christos 					break;
   1244       1.1  christos 			}
   1245       1.1  christos 			if (softa->ipf_auth_start == softa->ipf_auth_end) {
   1246       1.1  christos 				softa->ipf_auth_next = 0;
   1247       1.1  christos 				softa->ipf_auth_start = 0;
   1248       1.1  christos 				softa->ipf_auth_end = 0;
   1249       1.1  christos 			}
   1250       1.1  christos 		}
   1251       1.1  christos 		RWLOCK_EXIT(&softa->ipf_authlk);
   1252       1.1  christos 	}
   1253       1.1  christos #endif /* _KERNEL */
   1254       1.1  christos 	SPL_X(s);
   1255       1.1  christos 
   1256       1.1  christos 	return 0;
   1257       1.1  christos }
   1258       1.1  christos 
   1259       1.1  christos 
   1260       1.1  christos u_32_t
   1261       1.2  christos ipf_auth_pre_scanlist(ipf_main_softc_t *softc, fr_info_t *fin, u_32_t pass)
   1262       1.1  christos {
   1263       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
   1264       1.1  christos 
   1265       1.1  christos 	if (softa->ipf_auth_ip != NULL)
   1266       1.1  christos 		return ipf_scanlist(fin, softc->ipf_pass);
   1267       1.1  christos 
   1268       1.1  christos 	return pass;
   1269       1.1  christos }
   1270       1.1  christos 
   1271       1.1  christos 
   1272       1.1  christos frentry_t **
   1273       1.2  christos ipf_auth_rulehead(ipf_main_softc_t *softc)
   1274       1.1  christos {
   1275       1.1  christos 	ipf_auth_softc_t *softa = softc->ipf_auth_soft;
   1276       1.1  christos 
   1277       1.1  christos 	return &softa->ipf_auth_ip;
   1278       1.1  christos }
   1279