ip_auth.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
# define KERNEL 1
# define _KERNEL 1
#endif
#if !defined(_KERNEL)
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# define _KERNEL
# ifdef __OpenBSD__
struct file;
# endif
#endif
#else
#endif
#if defined(_KERNEL)
# endif
#endif
# include <sys/byteorder.h>
# ifdef _KERNEL
# include <sys/dditypes.h>
# endif
#endif
#endif
#endif
#endif
#ifdef sun
#endif
#include <netinet/in_systm.h>
# define KERNEL
# define _KERNEL
# define NOT_KERNEL
#endif
#ifdef NOT_KERNEL
#endif
#ifdef __sgi
# ifdef IFF_DRVRLOCK /* IRIX6 */
# endif
#endif
#else
# if !defined(__hpux)
# if __FreeBSD_version >= 300000
# if __FreeBSD_version >= 500042
# endif /* __FreeBSD_version >= 500042 */
# endif
# endif
#endif
#if SOLARIS2 >= 10
#include "ip_compat.h"
#include "ip_fil.h"
#include "ip_auth.h"
#else
#include "netinet/ip_compat.h"
#endif
#if !defined(MENTAT)
# ifdef __FreeBSD__
# endif
#endif
#if (__FreeBSD_version >= 300000)
# if defined(_KERNEL) && !defined(IPFILTER_LKM)
# endif
#endif
#if !defined(lint)
#endif
#ifdef USE_MUTEXES
extern ipfrwlock_t ipf_auth;
extern ipfmutex_t ipf_authmx;
# if SOLARIS
extern kcondvar_t ipfauthwait;
# endif /* SOLARIS */
#endif /* USE_MUTEXES */
int fr_authsize = FR_NUMAUTH;
int fr_authused = 0;
int fr_defaultauthage = 600;
int fr_auth_lock = 0;
int fr_auth_init = 0;
*fr_authlist = NULL;
int fr_authinit()
{
else
return -1;
if (fr_authpkts != NULL)
else
return -1;
#endif
fr_auth_init = 1;
return 0;
}
/*
* Check if a packet has authorization. If the packet is found to match an
* authorization result and that would result in a feedback loop (i.e. it
* will end up returning FR_AUTH) then return FR_BLOCK instead.
*/
{
int i;
if (fr_auth_lock || !fr_authused)
return NULL;
for (i = fr_authstart; i != fr_authend; ) {
/*
* index becomes -2 only after an SIOCAUTHW. Check this in
* case the same packet gets sent again and it hasn't yet been
* auth'd.
*/
/*
* Avoid feedback loop.
*/
/*
* Create a dummy rule for the stateful checking to
* use and return. Zero out any values we don't
* trust from userland!
*/
if (fr) {
}
} else
fr_authlist = fr;
}
fr_authused--;
if (i == fr_authstart) {
i++;
fra++;
if (i == fr_authsize) {
i = 0;
}
fr_authstart = i;
if (i == fr_authend)
break;
}
if (fr_authstart == fr_authend) {
fr_authnext = 0;
fr_authstart = fr_authend = 0;
}
}
return fr;
}
i++;
if (i == fr_authsize)
i = 0;
}
return NULL;
}
/*
* Check if we have room in the auth array to hold details for another packet.
* If we do, store it and wake up any user programs which are waiting to
* hear about these events.
*/
int fr_newauth(m, fin)
mb_t *m;
{
#endif
#endif
int i;
if (fr_auth_lock)
return 0;
if (fr_authstart > fr_authend) {
return 0;
} else {
if (fr_authused == fr_authsize) {
return 0;
}
}
fr_authused++;
i = fr_authend++;
if (fr_authend == fr_authsize)
fr_authend = 0;
/*
* No need to copyback here as we want to undo the changes, not keep
* them.
*/
# endif
{
}
#endif
#else
}
# endif
fr_authpkts[i] = m;
#endif
return 1;
}
#if defined(__NetBSD__) || defined(__OpenBSD__) || \
#else
int cmd;
#endif
int mode;
{
mb_t *m;
# ifdef USE_SPL
int s;
# endif /* USE_SPL */
#endif
char *t;
switch (cmd)
{
case SIOCSTLCK :
break;
}
break;
case SIOCATHST:
break;
case SIOCIPFFL:
SPL_NET(s);
i = fr_authflush();
SPL_X(s);
break;
case SIOCAUTHW:
/*
* Copy packet contents out to user space if
* requested. Bail on an error.
*/
m = fr_authpkts[fr_authnext];
t, i);
len -= i;
t += i;
if (error != 0)
break;
}
}
if (error != 0)
break;
SPL_NET(s);
fr_authnext++;
if (fr_authnext == fr_authsize)
fr_authnext = 0;
SPL_X(s);
return 0;
}
/*
* We exit ipf_global here because a program that enters in
* here will have a lock on it and goto sleep having this lock.
* If someone were to do an 'ipf -D' the system would then
* deadlock. The catch with releasing it here is that the
* caller of this function expects it to be held when we
* return so we have to reacquire it in here.
*/
#ifdef _KERNEL
# if SOLARIS
error = 0;
# else /* SOLARIS */
# ifdef __hpux
{
lock_t *l;
l = get_sleep_lock(&fr_authnext);
spinunlock(l);
}
# else
# ifdef __osf__
# else
# endif /* __osf__ */
# endif /* __hpux */
# endif /* SOLARIS */
#endif
if (error == 0) {
goto fr_authioctlloop;
}
break;
case SIOCAUTHR:
if (error != 0)
return error;
SPL_NET(s);
if ((i < 0) || (i >= fr_authsize) ||
SPL_X(s);
return ESRCH;
}
m = fr_authpkts[i];
fr_authpkts[i] = NULL;
#ifdef _KERNEL
# ifdef MENTAT
# else /* MENTAT */
NULL);
# else
# endif
# endif /* MENTAT */
if (error != 0)
else
} else if (m) {
# ifdef MENTAT
# else /* MENTAT */
m_freem(m);
} else {
IF_ENQUEUE(ifq, m);
# if IRIX < 605
# endif
}
# endif /* MENTAT */
if (error != 0)
else
} else
# ifdef MENTAT
if (error != 0)
# else /* MENTAT */
/*
* If we experience an error which will result in the packet
* not being processed, make sure we advance to the next one.
*/
fr_authused--;
if (i == fr_authstart) {
i++;
if (i == fr_authsize)
i = 0;
fr_authstart = i;
if (i == fr_authend)
break;
}
if (fr_authstart == fr_authend) {
fr_authnext = 0;
fr_authstart = fr_authend = 0;
}
}
}
# endif /* MENTAT */
#endif /* _KERNEL */
SPL_X(s);
break;
default :
break;
}
return error;
}
/*
* Free all network buffer memory used to keep saved packets.
*/
void fr_authunload()
{
register int i;
mb_t *m;
}
if (fr_authpkts != NULL) {
for (i = 0; i < fr_authsize; i++) {
m = fr_authpkts[i];
if (m != NULL) {
FREE_MB_T(m);
fr_authpkts[i] = NULL;
}
}
fr_authpkts = NULL;
}
}
if (fr_authlist != NULL) {
} else
}
}
if (fr_auth_init == 1) {
# endif
fr_auth_init = 0;
}
}
/*
* Slowly expire held auth records. Timeouts are set
* in expectation of this being called twice per second.
*/
void fr_authexpire()
{
register int i;
mb_t *m;
int s;
# endif
if (fr_auth_lock)
return;
SPL_NET(s);
FREE_MB_T(m);
fr_authpkts[i] = NULL;
fr_authused--;
}
}
} else
}
else
} else
}
SPL_X(s);
}
#if defined(__NetBSD__) || defined(__OpenBSD__) || \
#else
int cmd;
#endif
{
int error = 0;
int s;
#endif
return EIO;
break;
else
}
else {
SPL_NET(s);
SPL_X(s);
}
sizeof(*fr));
SPL_NET(s);
SPL_X(s);
} else
} else
return error;
}
/*
* Flush held packets.
* Must already be properly SPL'ed and Locked on &ipf_auth.
*
*/
int fr_authflush()
{
register int i, num_flushed;
mb_t *m;
if (fr_auth_lock)
return -1;
num_flushed = 0;
for (i = 0 ; i < fr_authsize; i++) {
m = fr_authpkts[i];
if (m != NULL) {
FREE_MB_T(m);
fr_authpkts[i] = NULL;
/* perhaps add & use a flush counter inst.*/
fr_authused--;
num_flushed++;
}
}
fr_authstart = 0;
fr_authend = 0;
fr_authnext = 0;
return num_flushed;
}