Sophie

Sophie

distrib > Mandriva > 2010.1 > i586 > media > main-testing-src > by-pkgid > 859ef07dcfa9bc598ebbccafde4e24f3 > files > 11

snort-2.8.6.1-0.1mdv2010.1.src.rpm

Index: snort-2.8.6/src/twofish.c
===================================================================
--- snort-2.8.6/src/twofish.c	(Revision 0)
+++ snort-2.8.6/src/twofish.c	(Revision 3)
@@ -0,0 +1,971 @@
+/* $Id: twofish.c,v 2.1 2008/12/15 20:36:05 fknobbe Exp $
+ *
+ *
+ * Copyright (C) 1997-2000 The Cryptix Foundation Limited.
+ * Copyright (C) 2000 Farm9.
+ * Copyright (C) 2001 Frank Knobbe.
+ * All rights reserved.
+ *
+ * For Cryptix code:
+ * Use, modification, copying and distribution of this software is subject
+ * the terms and conditions of the Cryptix General Licence. You should have
+ * received a copy of the Cryptix General Licence along with this library;
+ * if not, you can download a copy from http://www.cryptix.org/ .
+ *
+ * For Farm9:
+ * ---  jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and
+ *      ciphertext stealing technique, added AsciiTwofish class for easy encryption
+ *      decryption of text strings
+ *
+ * Frank Knobbe <frank@knobbe.us>:
+ * ---  April 2001, converted from C++ to C, prefixed global variables
+ *      with TwoFish, substituted some defines, changed functions to make use of
+ *      variables supplied in a struct, modified and added routines for modular calls.
+ *      Cleaned up the code so that defines are used instead of fixed 16's and 32's.
+ *      Created two general purpose crypt routines for one block and multiple block
+ *      encryption using Joh's CBC code.
+ *		Added crypt routines that use a header (with a magic and data length).
+ *		(Basically a major rewrite).
+ *
+ *      Note: Routines labeled _TwoFish are private and should not be used
+ *      (or with extreme caution).
+ *
+ */
+
+#ifndef __TWOFISH_LIBRARY_SOURCE__
+#define __TWOFISH_LIBRARY_SOURCE__
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#ifdef WIN32
+
+#ifndef u_long
+typedef unsigned long u_long;
+#endif
+#ifndef u_int32_t
+typedef unsigned long u_int32_t;
+#endif
+#ifndef u_word
+typedef unsigned short u_word;
+#endif
+#ifndef u_int16_t
+typedef unsigned short u_int16_t;
+#endif
+#ifndef u_char
+typedef unsigned char u_char;
+#endif
+#ifndef u_int8_t
+typedef unsigned char u_int8_t;
+#endif
+
+#endif /* WIN32 */
+
+#include "twofish.h"
+
+
+bool TwoFish_srand=TRUE;				/* if TRUE, first call of TwoFishInit will seed rand(); */
+										/* of TwoFishInit */
+
+/* Fixed 8x8 permutation S-boxes */
+static const u_int8_t TwoFish_P[2][256] =
+{
+    {  /* p0 */
+        0xA9, 0x67, 0xB3, 0xE8,   0x04, 0xFD, 0xA3, 0x76,   0x9A, 0x92, 0x80, 0x78,
+        0xE4, 0xDD, 0xD1, 0x38,   0x0D, 0xC6, 0x35, 0x98,   0x18, 0xF7, 0xEC, 0x6C,
+        0x43, 0x75, 0x37, 0x26,   0xFA, 0x13, 0x94, 0x48,   0xF2, 0xD0, 0x8B, 0x30,
+        0x84, 0x54, 0xDF, 0x23,   0x19, 0x5B, 0x3D, 0x59,   0xF3, 0xAE, 0xA2, 0x82,
+        0x63, 0x01, 0x83, 0x2E,   0xD9, 0x51, 0x9B, 0x7C,   0xA6, 0xEB, 0xA5, 0xBE,
+        0x16, 0x0C, 0xE3, 0x61,   0xC0, 0x8C, 0x3A, 0xF5,   0x73, 0x2C, 0x25, 0x0B,
+        0xBB, 0x4E, 0x89, 0x6B,   0x53, 0x6A, 0xB4, 0xF1,   0xE1, 0xE6, 0xBD, 0x45,
+        0xE2, 0xF4, 0xB6, 0x66,   0xCC, 0x95, 0x03, 0x56,   0xD4, 0x1C, 0x1E, 0xD7,
+        0xFB, 0xC3, 0x8E, 0xB5,   0xE9, 0xCF, 0xBF, 0xBA,   0xEA, 0x77, 0x39, 0xAF,
+        0x33, 0xC9, 0x62, 0x71,   0x81, 0x79, 0x09, 0xAD,   0x24, 0xCD, 0xF9, 0xD8,
+        0xE5, 0xC5, 0xB9, 0x4D,   0x44, 0x08, 0x86, 0xE7,   0xA1, 0x1D, 0xAA, 0xED,
+        0x06, 0x70, 0xB2, 0xD2,   0x41, 0x7B, 0xA0, 0x11,   0x31, 0xC2, 0x27, 0x90,
+        0x20, 0xF6, 0x60, 0xFF,   0x96, 0x5C, 0xB1, 0xAB,   0x9E, 0x9C, 0x52, 0x1B,
+        0x5F, 0x93, 0x0A, 0xEF,   0x91, 0x85, 0x49, 0xEE,   0x2D, 0x4F, 0x8F, 0x3B,
+        0x47, 0x87, 0x6D, 0x46,   0xD6, 0x3E, 0x69, 0x64,   0x2A, 0xCE, 0xCB, 0x2F,
+        0xFC, 0x97, 0x05, 0x7A,   0xAC, 0x7F, 0xD5, 0x1A,   0x4B, 0x0E, 0xA7, 0x5A,
+        0x28, 0x14, 0x3F, 0x29,   0x88, 0x3C, 0x4C, 0x02,   0xB8, 0xDA, 0xB0, 0x17,
+        0x55, 0x1F, 0x8A, 0x7D,   0x57, 0xC7, 0x8D, 0x74,   0xB7, 0xC4, 0x9F, 0x72,
+        0x7E, 0x15, 0x22, 0x12,   0x58, 0x07, 0x99, 0x34,   0x6E, 0x50, 0xDE, 0x68,
+        0x65, 0xBC, 0xDB, 0xF8,   0xC8, 0xA8, 0x2B, 0x40,   0xDC, 0xFE, 0x32, 0xA4,
+        0xCA, 0x10, 0x21, 0xF0,   0xD3, 0x5D, 0x0F, 0x00,   0x6F, 0x9D, 0x36, 0x42,
+        0x4A, 0x5E, 0xC1, 0xE0
+    },
+    {  /* p1 */
+        0x75, 0xF3, 0xC6, 0xF4,   0xDB, 0x7B, 0xFB, 0xC8,   0x4A, 0xD3, 0xE6, 0x6B,
+        0x45, 0x7D, 0xE8, 0x4B,   0xD6, 0x32, 0xD8, 0xFD,   0x37, 0x71, 0xF1, 0xE1,
+        0x30, 0x0F, 0xF8, 0x1B,   0x87, 0xFA, 0x06, 0x3F,   0x5E, 0xBA, 0xAE, 0x5B,
+        0x8A, 0x00, 0xBC, 0x9D,   0x6D, 0xC1, 0xB1, 0x0E,   0x80, 0x5D, 0xD2, 0xD5,
+        0xA0, 0x84, 0x07, 0x14,   0xB5, 0x90, 0x2C, 0xA3,   0xB2, 0x73, 0x4C, 0x54,
+        0x92, 0x74, 0x36, 0x51,   0x38, 0xB0, 0xBD, 0x5A,   0xFC, 0x60, 0x62, 0x96,
+        0x6C, 0x42, 0xF7, 0x10,   0x7C, 0x28, 0x27, 0x8C,   0x13, 0x95, 0x9C, 0xC7,
+        0x24, 0x46, 0x3B, 0x70,   0xCA, 0xE3, 0x85, 0xCB,   0x11, 0xD0, 0x93, 0xB8,
+        0xA6, 0x83, 0x20, 0xFF,   0x9F, 0x77, 0xC3, 0xCC,   0x03, 0x6F, 0x08, 0xBF,
+		0x40, 0xE7, 0x2B, 0xE2,   0x79, 0x0C, 0xAA, 0x82,   0x41, 0x3A, 0xEA, 0xB9,
+        0xE4, 0x9A, 0xA4, 0x97,   0x7E, 0xDA, 0x7A, 0x17,   0x66, 0x94, 0xA1, 0x1D,
+        0x3D, 0xF0, 0xDE, 0xB3,   0x0B, 0x72, 0xA7, 0x1C,   0xEF, 0xD1, 0x53, 0x3E,
+        0x8F, 0x33, 0x26, 0x5F,   0xEC, 0x76, 0x2A, 0x49,   0x81, 0x88, 0xEE, 0x21,
+        0xC4, 0x1A, 0xEB, 0xD9,   0xC5, 0x39, 0x99, 0xCD,   0xAD, 0x31, 0x8B, 0x01,
+        0x18, 0x23, 0xDD, 0x1F,   0x4E, 0x2D, 0xF9, 0x48,   0x4F, 0xF2, 0x65, 0x8E,
+        0x78, 0x5C, 0x58, 0x19,   0x8D, 0xE5, 0x98, 0x57,   0x67, 0x7F, 0x05, 0x64,
+        0xAF, 0x63, 0xB6, 0xFE,   0xF5, 0xB7, 0x3C, 0xA5,   0xCE, 0xE9, 0x68, 0x44,
+        0xE0, 0x4D, 0x43, 0x69,   0x29, 0x2E, 0xAC, 0x15,   0x59, 0xA8, 0x0A, 0x9E,
+        0x6E, 0x47, 0xDF, 0x34,   0x35, 0x6A, 0xCF, 0xDC,   0x22, 0xC9, 0xC0, 0x9B,
+        0x89, 0xD4, 0xED, 0xAB,   0x12, 0xA2, 0x0D, 0x52,   0xBB, 0x02, 0x2F, 0xA9,
+        0xD7, 0x61, 0x1E, 0xB4,   0x50, 0x04, 0xF6, 0xC2,   0x16, 0x25, 0x86, 0x56,
+        0x55, 0x09, 0xBE, 0x91
+    }
+};
+
+static bool TwoFish_MDSready=FALSE;
+static u_int32_t TwoFish_MDS[4][256]; /* TwoFish_MDS matrix */
+
+
+#define	TwoFish_LFSR1(x) (((x)>>1)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/2:0))
+#define	TwoFish_LFSR2(x) (((x)>>2)^(((x)&0x02)?TwoFish_MDS_GF_FDBK/2:0)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/4:0))
+
+#define	TwoFish_Mx_1(x) ((u_int32_t)(x))		/* force result to dword so << will work  */
+#define	TwoFish_Mx_X(x) ((u_int32_t)((x)^TwoFish_LFSR2(x)))	/* 5B */
+#define	TwoFish_Mx_Y(x) ((u_int32_t)((x)^TwoFish_LFSR1(x)^TwoFish_LFSR2(x)))	/* EF  */
+#define	TwoFish_RS_rem(x) { u_int8_t b=(u_int8_t)(x>>24); u_int32_t g2=((b<<1)^((b&0x80)?TwoFish_RS_GF_FDBK:0))&0xFF; u_int32_t g3=((b>>1)&0x7F)^((b&1)?TwoFish_RS_GF_FDBK>>1:0)^g2; x=(x<<8)^(g3<<24)^(g2<<16)^(g3<<8)^b; }
+
+/*#define	TwoFish__b(x,N)	(((u_int8_t *)&x)[((N)&3)^TwoFish_ADDR_XOR])*/ /* pick bytes out of a dword */
+
+#define	TwoFish_b0(x)			TwoFish__b(x,0)		/* extract LSB of u_int32_t  */
+#define	TwoFish_b1(x)			TwoFish__b(x,1)
+#define	TwoFish_b2(x)			TwoFish__b(x,2)
+#define	TwoFish_b3(x)			TwoFish__b(x,3)		/* extract MSB of u_int32_t  */
+
+u_int8_t TwoFish__b(u_int32_t x,int n)
+{	n&=3;
+	while(n-->0)
+		x>>=8;
+	return (u_int8_t)x;
+}
+
+
+/*	TwoFish Initialization
+ *
+ *	This routine generates a global data structure for use with TwoFish,
+ *	initializes important values (such as subkeys, sBoxes), generates subkeys
+ *	and precomputes the MDS matrix if not already done.
+ *
+ *	Input:	User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!')
+ *
+ *  Output:	Pointer to TWOFISH structure. This data structure contains key dependent data.
+ *			This pointer is used with all other crypt functions.
+ */
+
+TWOFISH *TwoFishInit(char *userkey)
+{   TWOFISH *tfdata;
+	int i,x,m;
+	char tkey[TwoFish_KEY_LENGTH+40];
+
+	tfdata=malloc(sizeof(TWOFISH));			/* allocate the TwoFish structure */
+	if(tfdata!=NULL)
+	{	if(*userkey)
+		{	strncpy(tkey,userkey,TwoFish_KEY_LENGTH);			/* use first 32 chars of user supplied password */
+			tkey[TwoFish_KEY_LENGTH]=0;							/* make sure it wasn't more */
+		}
+		else
+			strcpy(tkey,TwoFish_DEFAULT_PW);	/* if no key defined, use default password */
+		for(i=0,x=0,m=strlen(tkey);i<TwoFish_KEY_LENGTH;i++)	/* copy into data structure */
+		{	tfdata->key[i]=tkey[x++];							/* fill the whole keyspace with repeating key. */
+			if(x==m)
+				x=0;
+		}
+
+		if(!TwoFish_MDSready)
+			_TwoFish_PrecomputeMDSmatrix();		/* "Wake Up, Neo" */
+		_TwoFish_MakeSubKeys(tfdata);			/* generate subkeys */
+		_TwoFish_ResetCBC(tfdata);				/* reset the CBC */
+		tfdata->output=NULL;					/* nothing to output yet */
+		tfdata->dontflush=FALSE;				/* reset decrypt skip block flag */
+		if(TwoFish_srand)
+		{	TwoFish_srand=FALSE;
+			srand(time(NULL));
+		}
+	}
+	return tfdata;							/* return the data pointer */
+}
+
+
+void TwoFishDestroy(TWOFISH *tfdata)
+{	if(tfdata!=NULL)
+		free(tfdata);
+}
+
+
+/* en/decryption with CBC mode */
+unsigned long _TwoFish_CryptRawCBC(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata)
+{	unsigned long rl;
+
+	rl=len;											/* remember how much data to crypt. */
+	while(len>TwoFish_BLOCK_SIZE)					/* and now we process block by block. */
+	{	_TwoFish_BlockCrypt(in,out,TwoFish_BLOCK_SIZE,decrypt,tfdata); /* de/encrypt it. */
+		in+=TwoFish_BLOCK_SIZE;						/* adjust pointers. */
+		out+=TwoFish_BLOCK_SIZE;
+		len-=TwoFish_BLOCK_SIZE;
+	}
+	if(len>0)										/* if we have less than a block left... */
+		_TwoFish_BlockCrypt(in,out,len,decrypt,tfdata);	/* ...then we de/encrypt that too. */
+	if(tfdata->qBlockDefined && !tfdata->dontflush)						/* in case len was exactly one block... */
+		_TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); /* ...we need to write the...  */
+																		/* ...remaining bytes of the buffer */
+	return rl;
+}
+
+/* en/decryption on one block only */
+unsigned long _TwoFish_CryptRaw16(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata)
+{	/* qBlockPlain already zero'ed through ResetCBC  */
+	memcpy(tfdata->qBlockPlain,in,len);					/* toss the data into it. */
+	_TwoFish_BlockCrypt16(tfdata->qBlockPlain,tfdata->qBlockCrypt,decrypt,tfdata); /* encrypt just that block without CBC. */
+	memcpy(out,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE);				/* and return what we got */
+	return TwoFish_BLOCK_SIZE;
+}
+
+/* en/decryption without reset of CBC and output assignment */
+unsigned long _TwoFish_CryptRaw(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata)
+{
+	if(in!=NULL && out!=NULL && len>0 && tfdata!=NULL)		/* if we have valid data, then... */
+	{	if(len>TwoFish_BLOCK_SIZE)							/* ...check if we have more than one block. */
+			return _TwoFish_CryptRawCBC(in,out,len,decrypt,tfdata); /* if so, use the CBC routines... */
+		else
+			return _TwoFish_CryptRaw16(in,out,len,decrypt,tfdata); /* ...otherwise just do one block. */
+	}
+	return 0;
+}
+
+
+/*	TwoFish Raw Encryption
+ *
+ *	Does not use header, but does use CBC (if more than one block has to be encrypted).
+ *
+ *	Input:	Pointer to the buffer of the plaintext to be encrypted.
+ *			Pointer to the buffer receiving the ciphertext.
+ *			The length of the plaintext buffer.
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes encrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishEncryptRaw(char *in,
+								char *out,
+								unsigned long len,
+								TWOFISH *tfdata)
+{	_TwoFish_ResetCBC(tfdata);							/* reset CBC flag. */
+	tfdata->output=out;							/* output straight into output buffer. */
+	return _TwoFish_CryptRaw(in,out,len,FALSE,tfdata);	/* and go for it. */
+}
+
+/*	TwoFish Raw Decryption
+ *
+ *	Does not use header, but does use CBC (if more than one block has to be decrypted).
+ *
+ *	Input:	Pointer to the buffer of the ciphertext to be decrypted.
+ *			Pointer to the buffer receiving the plaintext.
+ *			The length of the ciphertext buffer (at least one cipher block).
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes decrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishDecryptRaw(char *in,
+								char *out,
+								unsigned long len,
+								TWOFISH *tfdata)
+{	_TwoFish_ResetCBC(tfdata);							/* reset CBC flag. */
+	tfdata->output=out;							/* output straight into output buffer. */
+	return _TwoFish_CryptRaw(in,out,len,TRUE,tfdata);	/* and go for it. */
+}
+
+/*	TwoFish Free
+ *
+ *	Free's the allocated buffer.
+ *
+ *	Input:	Pointer to the TwoFish structure
+ *
+ *	Output:	(none)
+ */
+
+void TwoFishFree(TWOFISH *tfdata)
+{	if(tfdata->output!=NULL)	/* if a valid buffer is present... */
+	{	free(tfdata->output);	/* ...then we free it for you... */
+		tfdata->output=NULL;	/* ...and mark as such. */
+	}
+}
+
+/*	TwoFish Set Output
+ *
+ *	If you want to allocate the output buffer yourself,
+ *	then you can set it with this function.
+ *
+ *	Input:	Pointer to your output buffer
+ *			Pointer to the TwoFish structure
+ *
+ *	Output:	(none)
+ */
+
+void TwoFishSetOutput(char *outp,TWOFISH *tfdata)
+{	tfdata->output=outp;				/* (do we really need a function for this?) */
+}
+
+/*	TwoFish Alloc
+ *
+ *	Allocates enough memory for the output buffer that would be required
+ *
+ *	Input:	Length of the plaintext.
+ *			Boolean flag for BinHex Output.
+ *			Pointer to the TwoFish structure.
+ *
+ *	Output:	Returns a pointer to the memory allocated.
+ */
+
+void *TwoFishAlloc(unsigned long len,bool binhex,bool decrypt,TWOFISH *tfdata)
+{
+/*	TwoFishFree(tfdata);	*/			/* (don't for now) discard whatever was allocated earlier. */
+	if(decrypt)							/* if decrypting... */
+	{	if(binhex)						/* ...and input is binhex encoded... */
+			len/=2;						/* ...use half as much for output. */
+		len-=TwoFish_BLOCK_SIZE;		/* Also, subtract the size of the header. */
+	}
+	else
+	{	len+=TwoFish_BLOCK_SIZE;		/* the size is just increased by the header... */
+		if(binhex)
+			len*=2;						/* ...and doubled if output is to be binhexed. */
+	}
+	tfdata->output=malloc(len+TwoFish_BLOCK_SIZE);/* grab some memory...plus some extra (it's running over somewhere, crashes without extra padding) */
+
+	return tfdata->output;				/* ...and return to caller. */
+}
+
+/* bin2hex and hex2bin conversion */
+void _TwoFish_BinHex(u_int8_t *buf,unsigned long len,bool bintohex)
+{	u_int8_t *pi,*po,c;
+
+	if(bintohex)
+	{	for(pi=buf+len-1,po=buf+(2*len)-1;len>0;pi--,po--,len--) /* let's start from the end of the bin block. */
+		{	c=*pi;												 /* grab value. */
+			c&=15;												 /* use lower 4 bits. */
+			if(c>9)												 /* convert to ascii. */
+				c+=('a'-10);
+			else
+				c+='0';
+			*po--=c;											 /* set the lower nibble. */
+			c=*pi;												 /* grab value again. */
+			c>>=4;												 /* right shift 4 bits. */
+			c&=15;												 /* make sure we only have 4 bits. */
+			if(c>9)												 /* convert to ascii. */
+				c+=('a'-10);
+			else
+				c+='0';
+			*po=c;												 /* set the higher nibble. */
+		}														 /* and keep going. */
+	}
+	else
+	{	for(pi=buf,po=buf;len>0;pi++,po++,len-=2)				 /* let's start from the beginning of the hex block. */
+		{	c=tolower(*pi++)-'0';								 /* grab higher nibble. */
+			if(c>9)												 /* convert to value. */
+				c-=('0'-9);
+			*po=c<<4;											 /* left shit 4 bits. */
+			c=tolower(*pi)-'0';									 /* grab lower nibble. */
+			if(c>9)												 /* convert to value. */
+				c-=('0'-9);
+			*po|=c;												 /* and add to value. */
+		}
+	}
+}
+
+
+/*	TwoFish Encryption
+ *
+ *	Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ *  this routine will alloc the memory. In addition, it will include a small 'header'
+ *  containing the magic and some salt. That way the decrypt routine can check if the
+ *  packet got decrypted successfully, and return 0 instead of garbage.
+ *
+ *	Input:	Pointer to the buffer of the plaintext to be encrypted.
+ *			Pointer to the pointer to the buffer receiving the ciphertext.
+ *				The pointer either points to user allocated output buffer space, or to NULL, in which case
+ *				this routine will set the pointer to the buffer allocated through the struct.
+ *			The length of the plaintext buffer.
+ *				Can be -1 if the input is a null terminated string, in which case we'll count for you.
+ *			Boolean flag for BinHex Output (if used, output will be twice as large as input).
+ *				Note: BinHex conversion overwrites (converts) input buffer!
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes encrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishEncrypt(char *in,
+							 char **out,
+							 signed long len,
+							 bool binhex,
+							 TWOFISH *tfdata)
+{	unsigned long ilen,olen;
+
+
+	if(len== -1)			/* if we got -1 for len, we'll assume IN is a...  */
+		ilen=strlen(in);	/* ...\0 terminated string and figure len out ourselves... */
+	else
+		ilen=len;			/* ...otherwise we trust you supply a correct length. */
+
+	if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */
+	{	if(*out==NULL)									/* if OUT points to a NULL pointer... */
+			*out=TwoFishAlloc(ilen,binhex,FALSE,tfdata);  /* ...we'll (re-)allocate buffer space. */
+		if(*out!=NULL)
+		{	tfdata->output=*out;							/* set output buffer. */
+			tfdata->header.salt=rand()*65536+rand();		/* toss in some salt. */
+			tfdata->header.length[0]= (u_int8_t)(ilen);
+			tfdata->header.length[1]= (u_int8_t)(ilen>>8);
+			tfdata->header.length[2]= (u_int8_t)(ilen>>16);
+			tfdata->header.length[3]= (u_int8_t)(ilen>>24);
+			memcpy(tfdata->header.magic,TwoFish_MAGIC,TwoFish_MAGIC_LEN); /* set the magic. */
+			olen=TwoFish_BLOCK_SIZE;						/* set output counter. */
+			_TwoFish_ResetCBC(tfdata);						/* reset the CBC flag */
+			_TwoFish_BlockCrypt((u_int8_t *)&(tfdata->header),*out,olen,FALSE,tfdata); /* encrypt first block (without flush on 16 byte boundary). */
+			olen+=_TwoFish_CryptRawCBC(in,*out+TwoFish_BLOCK_SIZE,ilen,FALSE,tfdata);	/* and encrypt the rest (we do not reset the CBC flag). */
+			if(binhex)									/* if binhex... */
+			{	_TwoFish_BinHex(*out,olen,TRUE);		/* ...convert output to binhex... */
+				olen*=2;								/* ...and size twice as large. */
+			}
+			tfdata->output=*out;
+			return olen;
+		}
+	}
+	return 0;
+}
+
+/*	TwoFish Decryption
+ *
+ *	Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ *  this routine will alloc the memory. In addition, it will check the small 'header'
+ *  containing the magic. If magic does not match we return 0. Otherwise we return the
+ *  amount of bytes decrypted (should be the same as the length in the header).
+ *
+ *	Input:	Pointer to the buffer of the ciphertext to be decrypted.
+ *			Pointer to the pointer to the buffer receiving the plaintext.
+ *				The pointer either points to user allocated output buffer space, or to NULL, in which case
+ *				this routine will set the pointer to the buffer allocated through the struct.
+ *			The length of the ciphertext buffer.
+ *				Can be -1 if the input is a null terminated binhex string, in which case we'll count for you.
+ *			Boolean flag for BinHex Input (if used, plaintext will be half as large as input).
+ *				Note: BinHex conversion overwrites (converts) input buffer!
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes decrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishDecrypt(char *in,
+							 char **out,
+							 signed long len,
+							 bool binhex,
+							 TWOFISH *tfdata)
+{	unsigned long ilen,elen,olen;
+	const u_int8_t cmagic[TwoFish_MAGIC_LEN]=TwoFish_MAGIC;
+	u_int8_t *tbuf;
+
+
+
+	if(len== -1)			/* if we got -1 for len, we'll assume IN is...  */
+		ilen=strlen(in);	/* ...\0 terminated binhex and figure len out ourselves... */
+	else
+		ilen=len;			/* ...otherwise we trust you supply a correct length. */
+
+	if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */
+	{	if(*out==NULL)									/* if OUT points to a NULL pointer... */
+			*out=TwoFishAlloc(ilen,binhex,TRUE,tfdata); /* ...we'll (re-)allocate buffer space. */
+		if(*out!=NULL)
+		{	if(binhex)									/* if binhex... */
+			{	_TwoFish_BinHex(in,ilen,FALSE);		/* ...convert input to values... */
+				ilen/=2;								/* ...and size half as much. */
+			}
+			_TwoFish_ResetCBC(tfdata);						/* reset the CBC flag. */
+
+			tbuf=(u_int8_t *)malloc(ilen+TwoFish_BLOCK_SIZE); /* get memory for data and header. */
+			if(tbuf==NULL)
+				return 0;
+			tfdata->output=tbuf;					/* set output to temp buffer. */
+
+			olen=_TwoFish_CryptRawCBC(in,tbuf,ilen,TRUE,tfdata)-TwoFish_BLOCK_SIZE; /* decrypt the whole thing. */
+			memcpy(&(tfdata->header),tbuf,TwoFish_BLOCK_SIZE); /* copy first block into header. */
+			tfdata->output=*out;
+			for(elen=0;elen<TwoFish_MAGIC_LEN;elen++)	/* compare magic. */
+				if(tfdata->header.magic[elen]!=cmagic[elen])
+					break;
+			if(elen==TwoFish_MAGIC_LEN)					/* if magic matches then... */
+			{	elen=(tfdata->header.length[0]) |
+					 (tfdata->header.length[1])<<8 |
+					 (tfdata->header.length[2])<<16 |
+					 (tfdata->header.length[3])<<24;	/* .. we know how much to expect. */
+				if(elen>olen)							/* adjust if necessary. */
+					elen=olen;
+				memcpy(*out,tbuf+TwoFish_BLOCK_SIZE,elen);	/* copy data into intended output. */
+				free(tbuf);
+				return elen;
+			}
+			free(tbuf);
+		}
+	}
+	return 0;
+}
+
+void _TwoFish_PrecomputeMDSmatrix(void)	/* precompute the TwoFish_MDS matrix */
+{   u_int32_t m1[2];
+    u_int32_t mX[2];
+    u_int32_t mY[2];
+    u_int32_t i, j;
+
+    for (i = 0; i < 256; i++)
+    {   j = TwoFish_P[0][i]       & 0xFF; /* compute all the matrix elements */
+        m1[0] = j;
+        mX[0] = TwoFish_Mx_X( j ) & 0xFF;
+        mY[0] = TwoFish_Mx_Y( j ) & 0xFF;
+
+        j = TwoFish_P[1][i]       & 0xFF;
+        m1[1] = j;
+        mX[1] = TwoFish_Mx_X( j ) & 0xFF;
+        mY[1] = TwoFish_Mx_Y( j ) & 0xFF;
+
+        TwoFish_MDS[0][i] = m1[TwoFish_P_00] | /* fill matrix w/ above elements */
+                    mX[TwoFish_P_00] <<  8 |
+                    mY[TwoFish_P_00] << 16 |
+                    mY[TwoFish_P_00] << 24;
+        TwoFish_MDS[1][i] = mY[TwoFish_P_10] |
+                    mY[TwoFish_P_10] <<  8 |
+                    mX[TwoFish_P_10] << 16 |
+                    m1[TwoFish_P_10] << 24;
+        TwoFish_MDS[2][i] = mX[TwoFish_P_20] |
+                    mY[TwoFish_P_20] <<  8 |
+                    m1[TwoFish_P_20] << 16 |
+                    mY[TwoFish_P_20] << 24;
+        TwoFish_MDS[3][i] = mX[TwoFish_P_30] |
+                    m1[TwoFish_P_30] <<  8 |
+                    mY[TwoFish_P_30] << 16 |
+                    mX[TwoFish_P_30] << 24;
+    }
+	TwoFish_MDSready=TRUE;
+}
+
+
+void _TwoFish_MakeSubKeys(TWOFISH *tfdata)	/* Expand a user-supplied key material into a session key. */
+{	u_int32_t k64Cnt    = TwoFish_KEY_LENGTH / 8;
+	u_int32_t k32e[4]; /* even 32-bit entities */
+	u_int32_t k32o[4]; /* odd 32-bit entities */
+	u_int32_t sBoxKey[4];
+	u_int32_t offset,i,j;
+	u_int32_t A, B, q=0;
+	u_int32_t k0,k1,k2,k3;
+    u_int32_t b0,b1,b2,b3;
+
+    /* split user key material into even and odd 32-bit entities and */
+    /* compute S-box keys using (12, 8) Reed-Solomon code over GF(256) */
+
+
+    for (offset=0,i=0,j=k64Cnt-1;i<4 && offset<TwoFish_KEY_LENGTH;i++,j--)
+    {	k32e[i] = tfdata->key[offset++];
+		k32e[i]|= tfdata->key[offset++]<<8;
+		k32e[i]|= tfdata->key[offset++]<<16;
+		k32e[i]|= tfdata->key[offset++]<<24;
+    	k32o[i] = tfdata->key[offset++];
+		k32o[i]|= tfdata->key[offset++]<<8;
+		k32o[i]|= tfdata->key[offset++]<<16;
+		k32o[i]|= tfdata->key[offset++]<<24;
+        sBoxKey[j] = _TwoFish_RS_MDS_Encode( k32e[i], k32o[i] ); /* reverse order */
+    }
+
+    /* compute the round decryption subkeys for PHT. these same subkeys */
+    /* will be used in encryption but will be applied in reverse order. */
+    i=0;
+    while(i < TwoFish_TOTAL_SUBKEYS)
+    {	A = _TwoFish_F32( k64Cnt, q, k32e ); /* A uses even key entities */
+        q += TwoFish_SK_BUMP;
+
+        B = _TwoFish_F32( k64Cnt, q, k32o ); /* B uses odd  key entities */
+        q += TwoFish_SK_BUMP;
+
+        B = B << 8 | B >> 24;
+
+        A += B;
+        tfdata->subKeys[i++] = A;           /* combine with a PHT */
+
+        A += B;
+        tfdata->subKeys[i++] = A << TwoFish_SK_ROTL | A >> (32-TwoFish_SK_ROTL);
+    }
+
+    /* fully expand the table for speed */
+    k0 = sBoxKey[0];
+    k1 = sBoxKey[1];
+    k2 = sBoxKey[2];
+    k3 = sBoxKey[3];
+
+    for (i = 0; i < 256; i++)
+    {   b0 = b1 = b2 = b3 = i;
+        switch (k64Cnt & 3)
+        {	case 1: /* 64-bit keys */
+				tfdata->sBox[      2*i  ] = TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0]) ^ TwoFish_b0(k0)];
+				tfdata->sBox[      2*i+1] = TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1]) ^ TwoFish_b1(k0)];
+				tfdata->sBox[0x200+2*i  ] = TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2]) ^ TwoFish_b2(k0)];
+				tfdata->sBox[0x200+2*i+1] = TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3]) ^ TwoFish_b3(k0)];
+				break;
+			case 0: /* 256-bit keys (same as 4) */
+				b0 = (TwoFish_P[TwoFish_P_04][b0]) ^ TwoFish_b0(k3);
+				b1 = (TwoFish_P[TwoFish_P_14][b1]) ^ TwoFish_b1(k3);
+				b2 = (TwoFish_P[TwoFish_P_24][b2]) ^ TwoFish_b2(k3);
+				b3 = (TwoFish_P[TwoFish_P_34][b3]) ^ TwoFish_b3(k3);
+			case 3:  /* 192-bit keys */
+				b0 = (TwoFish_P[TwoFish_P_03][b0]) ^ TwoFish_b0(k2);
+				b1 = (TwoFish_P[TwoFish_P_13][b1]) ^ TwoFish_b1(k2);
+				b2 = (TwoFish_P[TwoFish_P_23][b2]) ^ TwoFish_b2(k2);
+				b3 = (TwoFish_P[TwoFish_P_33][b3]) ^ TwoFish_b3(k2);
+			case 2: /* 128-bit keys */
+				tfdata->sBox[      2*i  ]=
+					TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0]) ^
+					TwoFish_b0(k1)]) ^ TwoFish_b0(k0)];
+
+				tfdata->sBox[      2*i+1]=
+					TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1]) ^
+					TwoFish_b1(k1)]) ^ TwoFish_b1(k0)];
+
+				tfdata->sBox[0x200+2*i  ]=
+					TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2]) ^
+					TwoFish_b2(k1)]) ^ TwoFish_b2(k0)];
+
+				tfdata->sBox[0x200+2*i+1]=
+					TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3]) ^
+					TwoFish_b3(k1)]) ^ TwoFish_b3(k0)];
+		}
+    }
+}
+
+
+/**
+ * Encrypt or decrypt exactly one block of plaintext in CBC mode.
+ * Use "ciphertext stealing" technique described on pg. 196
+ * of "Applied Cryptography" to encrypt the final partial
+ * (i.e. <16 byte) block if necessary.
+ *
+ * jojo: the "ciphertext stealing" requires we read ahead and have
+ * special handling for the last two blocks.  Because of this, the
+ * output from the TwoFish algorithm is handled internally here.
+ * It would be better to have a higher level handle this as well as
+ * CBC mode.  Unfortunately, I've mixed the two together, which is
+ * pretty crappy... The Java version separates these out correctly.
+ *
+ * fknobbe:	I have reduced the CBC mode to work on memory buffer only.
+ *			Higher routines should use an intermediate buffer and handle
+ *			their output seperately (mainly so the data can be flushed
+ *			in one chunk, not seperate 16 byte blocks...)
+ *
+ * @param in   The plaintext.
+ * @param out  The ciphertext
+ * @param size how much to encrypt
+ * @param tfdata: Pointer to the global data structure containing session keys.
+ * @return none
+ */
+void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,unsigned long size,int decrypt,TWOFISH *tfdata)
+{	u_int8_t PnMinusOne[TwoFish_BLOCK_SIZE];
+	u_int8_t CnMinusOne[TwoFish_BLOCK_SIZE];
+	u_int8_t CBCplusCprime[TwoFish_BLOCK_SIZE];
+	u_int8_t Pn[TwoFish_BLOCK_SIZE];
+	u_int8_t *p,*pout;
+	unsigned long i;
+
+    /* here is where we implement CBC mode and cipher block stealing */
+    if(size==TwoFish_BLOCK_SIZE)
+	{   /* if we are encrypting, CBC means we XOR the plain text block with the */
+        /* previous cipher text block before encrypting */
+		if(!decrypt && tfdata->qBlockDefined)
+		{   for(p=in,i=0;i<TwoFish_BLOCK_SIZE;i++,p++)
+				Pn[i]=*p ^ tfdata->qBlockCrypt[i];	/* FK: I'm copying the xor'ed input into Pn... */
+		}
+		else
+			memcpy(Pn,in,TwoFish_BLOCK_SIZE); /* FK: same here. we work of Pn all the time. */
+
+        /* TwoFish block level encryption or decryption */
+		_TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata);
+
+        /* if we are decrypting, CBC means we XOR the result of the decryption */
+        /* with the previous cipher text block to get the resulting plain text */
+        if(decrypt && tfdata->qBlockDefined)
+        {	for (p=out,i=0;i<TwoFish_BLOCK_SIZE;i++,p++)
+				*p^=tfdata->qBlockPlain[i];
+        }
+
+        /* save the input and output blocks, since CBC needs these for XOR */
+        /* operations */
+        _TwoFish_qBlockPush(Pn,out,tfdata);
+	}
+	else
+	{   /* cipher block stealing, we are at Pn, */
+        /* but since Cn-1 must now be replaced with CnC' */
+        /* we pop it off, and recalculate Cn-1 */
+
+        if(decrypt)
+        {   /* We are on an odd block, and had to do cipher block stealing, */
+            /* so the PnMinusOne has to be derived differently. */
+
+            /* First we decrypt it into CBC and C' */
+	        _TwoFish_qBlockPop(CnMinusOne,PnMinusOne,tfdata);
+            _TwoFish_BlockCrypt16(CnMinusOne,CBCplusCprime,decrypt,tfdata);
+
+            /* we then xor the first few bytes with the "in" bytes (Cn) */
+            /* to recover Pn, which we put in out */
+            for(p=in,pout=out,i=0;i<size;i++,p++,pout++)
+                *pout=*p ^ CBCplusCprime[i];
+
+            /* We now recover the original CnMinusOne, which consists of */
+            /* the first "size" bytes of "in" data, followed by the */
+            /* "Cprime" portion of CBCplusCprime */
+            for(p=in,i=0;i<size;i++,p++)
+                CnMinusOne[i]=*p;
+            for(;i<TwoFish_BLOCK_SIZE;i++)
+                CnMinusOne[i]=CBCplusCprime[i];
+
+            /* we now decrypt CnMinusOne to get PnMinusOne xored with Cn-2 */
+            _TwoFish_BlockCrypt16(CnMinusOne,PnMinusOne,decrypt,tfdata);
+
+            for(i=0;i<TwoFish_BLOCK_SIZE;i++)
+                PnMinusOne[i]=PnMinusOne[i] ^ tfdata->prevCipher[i];
+
+            /* So at this point, out has PnMinusOne */
+            _TwoFish_qBlockPush(CnMinusOne,PnMinusOne,tfdata);
+		    _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+            _TwoFish_FlushOutput(out,size,tfdata);
+        }
+		else
+		{	_TwoFish_qBlockPop(PnMinusOne,CnMinusOne,tfdata);
+			memset(Pn,0,TwoFish_BLOCK_SIZE);
+			memcpy(Pn,in,size);
+			for(i=0;i<TwoFish_BLOCK_SIZE;i++)
+				Pn[i]^=CnMinusOne[i];
+			_TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata);
+			_TwoFish_qBlockPush(Pn,out,tfdata);  /* now we officially have Cn-1 */
+			_TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+			_TwoFish_FlushOutput(CnMinusOne,size,tfdata);  /* old Cn-1 becomes new partial Cn */
+		}
+		tfdata->qBlockDefined=FALSE;
+	}
+}
+
+void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata)
+{	if(tfdata->qBlockDefined)
+		_TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+	memcpy(tfdata->prevCipher,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE);
+	memcpy(tfdata->qBlockPlain,p,TwoFish_BLOCK_SIZE);
+	memcpy(tfdata->qBlockCrypt,c,TwoFish_BLOCK_SIZE);
+	tfdata->qBlockDefined=TRUE;
+}
+
+void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata)
+{	memcpy(p,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE );
+	memcpy(c,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE );
+	tfdata->qBlockDefined=FALSE;
+}
+
+/* Reset's the CBC flag and zero's PrevCipher (through qBlockPlain) (important) */
+void _TwoFish_ResetCBC(TWOFISH *tfdata)
+{	tfdata->qBlockDefined=FALSE;
+	memset(tfdata->qBlockPlain,0,TwoFish_BLOCK_SIZE);
+}
+
+void _TwoFish_FlushOutput(u_int8_t *b,unsigned long len,TWOFISH *tfdata)
+{	unsigned long i;
+
+	for(i=0;i<len && !tfdata->dontflush;i++)
+		*tfdata->output++ = *b++;
+	tfdata->dontflush=FALSE;
+}
+
+void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata)
+{	u_int32_t x0,x1,x2,x3;
+    u_int32_t k,t0,t1,R;
+
+
+	x0=*in++;
+	x0|=(*in++ << 8 );
+	x0|=(*in++ << 16);
+	x0|=(*in++ << 24);
+    x1=*in++;
+	x1|=(*in++ << 8 );
+	x1|=(*in++ << 16);
+	x1|=(*in++ << 24);
+	x2=*in++;
+	x2|=(*in++ << 8 );
+	x2|=(*in++ << 16);
+	x2|=(*in++ << 24);
+	x3=*in++;
+	x3|=(*in++ << 8 );
+	x3|=(*in++ << 16);
+	x3|=(*in++ << 24);
+
+	if(decrypt)
+    {	x0 ^= tfdata->subKeys[4];	/* swap input and output whitening keys when decrypting */
+ 	    x1 ^= tfdata->subKeys[5];
+		x2 ^= tfdata->subKeys[6];
+		x3 ^= tfdata->subKeys[7];
+
+        k = 7+(TwoFish_ROUNDS*2);
+        for (R = 0; R < TwoFish_ROUNDS; R += 2)
+		{   t0 = _TwoFish_Fe320( tfdata->sBox, x0);
+            t1 = _TwoFish_Fe323( tfdata->sBox, x1);
+            x3 ^= t0 + (t1<<1) + tfdata->subKeys[k--];
+            x3  = x3 >> 1 | x3 << 31;
+            x2  = x2 << 1 | x2 >> 31;
+            x2 ^= t0 + t1 + tfdata->subKeys[k--];
+
+            t0 = _TwoFish_Fe320( tfdata->sBox, x2);
+            t1 = _TwoFish_Fe323( tfdata->sBox, x3);
+            x1 ^= t0 + (t1<<1) + tfdata->subKeys[k--];
+            x1  = x1 >> 1 | x1 << 31;
+            x0  = x0 << 1 | x0 >> 31;
+            x0 ^= t0 + t1 + tfdata->subKeys[k--];
+        }
+
+		x2 ^= tfdata->subKeys[0];
+		x3 ^= tfdata->subKeys[1];
+		x0 ^= tfdata->subKeys[2];
+		x1 ^= tfdata->subKeys[3];
+	}
+	else
+    {	x0 ^= tfdata->subKeys[0];
+	    x1 ^= tfdata->subKeys[1];
+		x2 ^= tfdata->subKeys[2];
+		x3 ^= tfdata->subKeys[3];
+
+		k = 8;
+        for (R = 0; R < TwoFish_ROUNDS; R += 2)
+        {   t0 = _TwoFish_Fe320( tfdata->sBox, x0);
+            t1 = _TwoFish_Fe323( tfdata->sBox, x1);
+            x2 ^= t0 + t1 + tfdata->subKeys[k++];
+            x2  = x2 >> 1 | x2 << 31;
+            x3  = x3 << 1 | x3 >> 31;
+            x3 ^= t0 + (t1<<1) + tfdata->subKeys[k++];
+
+            t0 = _TwoFish_Fe320( tfdata->sBox, x2);
+            t1 = _TwoFish_Fe323( tfdata->sBox, x3);
+            x0 ^= t0 + t1 + tfdata->subKeys[k++];
+            x0  = x0 >> 1 | x0 << 31;
+            x1  = x1 << 1 | x1 >> 31;
+            x1 ^= t0 + (t1<<1) + tfdata->subKeys[k++];
+        }
+
+		x2 ^= tfdata->subKeys[4];
+		x3 ^= tfdata->subKeys[5];
+		x0 ^= tfdata->subKeys[6];
+		x1 ^= tfdata->subKeys[7];
+	}
+
+	*out++ = (u_int8_t)(x2      );
+    *out++ = (u_int8_t)(x2 >>  8);
+    *out++ = (u_int8_t)(x2 >> 16);
+    *out++ = (u_int8_t)(x2 >> 24);
+
+    *out++ = (u_int8_t)(x3      );
+    *out++ = (u_int8_t)(x3 >>  8);
+    *out++ = (u_int8_t)(x3 >> 16);
+    *out++ = (u_int8_t)(x3 >> 24);
+
+    *out++ = (u_int8_t)(x0      );
+    *out++ = (u_int8_t)(x0 >>  8);
+    *out++ = (u_int8_t)(x0 >> 16);
+    *out++ = (u_int8_t)(x0 >> 24);
+
+    *out++ = (u_int8_t)(x1      );
+    *out++ = (u_int8_t)(x1 >>  8);
+    *out++ = (u_int8_t)(x1 >> 16);
+    *out++ = (u_int8_t)(x1 >> 24);
+}
+
+/**
+ * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box
+ * 32-bit entity from two key material 32-bit entities.
+ *
+ * @param  k0  1st 32-bit entity.
+ * @param  k1  2nd 32-bit entity.
+ * @return  Remainder polynomial generated using RS code
+ */
+u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1)
+{	u_int32_t i,r;
+
+    for(r=k1,i=0;i<4;i++) /* shift 1 byte at a time */
+        TwoFish_RS_rem(r);
+    r ^= k0;
+    for(i=0;i<4;i++)
+        TwoFish_RS_rem(r);
+
+    return r;
+}
+
+u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32)
+{   u_int8_t b0,b1,b2,b3;
+	u_int32_t k0,k1,k2,k3,result = 0;
+
+	b0=TwoFish_b0(x);
+    b1=TwoFish_b1(x);
+    b2=TwoFish_b2(x);
+    b3=TwoFish_b3(x);
+    k0=k32[0];
+    k1=k32[1];
+    k2=k32[2];
+    k3=k32[3];
+
+    switch (k64Cnt & 3)
+    {	case 1:	/* 64-bit keys */
+			result =
+				TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0] & 0xFF) ^ TwoFish_b0(k0)] ^
+				TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1] & 0xFF) ^ TwoFish_b1(k0)] ^
+				TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2] & 0xFF) ^ TwoFish_b2(k0)] ^
+				TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3] & 0xFF) ^ TwoFish_b3(k0)];
+        break;
+		case 0:	/* 256-bit keys (same as 4) */
+			b0 = (TwoFish_P[TwoFish_P_04][b0] & 0xFF) ^ TwoFish_b0(k3);
+			b1 = (TwoFish_P[TwoFish_P_14][b1] & 0xFF) ^ TwoFish_b1(k3);
+			b2 = (TwoFish_P[TwoFish_P_24][b2] & 0xFF) ^ TwoFish_b2(k3);
+			b3 = (TwoFish_P[TwoFish_P_34][b3] & 0xFF) ^ TwoFish_b3(k3);
+
+		case 3:	/* 192-bit keys */
+			b0 = (TwoFish_P[TwoFish_P_03][b0] & 0xFF) ^ TwoFish_b0(k2);
+			b1 = (TwoFish_P[TwoFish_P_13][b1] & 0xFF) ^ TwoFish_b1(k2);
+			b2 = (TwoFish_P[TwoFish_P_23][b2] & 0xFF) ^ TwoFish_b2(k2);
+			b3 = (TwoFish_P[TwoFish_P_33][b3] & 0xFF) ^ TwoFish_b3(k2);
+		case 2:	/* 128-bit keys (optimize for this case) */
+			result =
+				  TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0] & 0xFF) ^ TwoFish_b0(k1)] & 0xFF) ^ TwoFish_b0(k0)] ^
+				  TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1] & 0xFF) ^ TwoFish_b1(k1)] & 0xFF) ^ TwoFish_b1(k0)] ^
+				  TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2] & 0xFF) ^ TwoFish_b2(k1)] & 0xFF) ^ TwoFish_b2(k0)] ^
+				  TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3] & 0xFF) ^ TwoFish_b3(k1)] & 0xFF) ^ TwoFish_b3(k0)];
+        break;
+    }
+    return result;
+}
+
+u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x)
+{   return lsBox[        TwoFish_b0(x)<<1    ]^
+           lsBox[      ((TwoFish_b1(x)<<1)|1)]^
+           lsBox[0x200+ (TwoFish_b2(x)<<1)   ]^
+           lsBox[0x200+((TwoFish_b3(x)<<1)|1)];
+}
+
+u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x)
+{   return lsBox[       (TwoFish_b3(x)<<1)   ]^
+           lsBox[      ((TwoFish_b0(x)<<1)|1)]^
+           lsBox[0x200+ (TwoFish_b1(x)<<1)   ]^
+           lsBox[0x200+((TwoFish_b2(x)<<1)|1)];
+}
+
+u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R)
+{   return lsBox[      2*TwoFish__b(x,R  )  ]^
+           lsBox[      2*TwoFish__b(x,R+1)+1]^
+           lsBox[0x200+2*TwoFish__b(x,R+2)  ]^
+           lsBox[0x200+2*TwoFish__b(x,R+3)+1];
+}
+
+
+#endif

Index: snort-2.8.6/src/twofish.h
===================================================================
--- snort-2.8.6/src/twofish.h	(Revision 0)
+++ snort-2.8.6/src/twofish.h	(Revision 3)
@@ -0,0 +1,276 @@
+/* $Id: twofish.h,v 2.1 2008/12/15 20:36:05 fknobbe Exp $
+ *
+ *
+ * Copyright (C) 1997-2000 The Cryptix Foundation Limited.
+ * Copyright (C) 2000 Farm9.
+ * Copyright (C) 2001 Frank Knobbe.
+ * All rights reserved.
+ *
+ * For Cryptix code:
+ * Use, modification, copying and distribution of this software is subject
+ * the terms and conditions of the Cryptix General Licence. You should have
+ * received a copy of the Cryptix General Licence along with this library;
+ * if not, you can download a copy from http://www.cryptix.org/ .
+ *
+ * For Farm9:
+ * ---  jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and
+ *      ciphertext stealing technique, added AsciiTwofish class for easy encryption
+ *      decryption of text strings
+ *
+ * Frank Knobbe <frank@knobbe.us>:
+ * ---  April 2001, converted from C++ to C, prefixed global variables
+ *      with TwoFish, substituted some defines, changed functions to make use of
+ *      variables supplied in a struct, modified and added routines for modular calls.
+ *      Cleaned up the code so that defines are used instead of fixed 16's and 32's.
+ *      Created two general purpose crypt routines for one block and multiple block
+ *      encryption using Joh's CBC code.
+ *		Added crypt routines that use a header (with a magic and data length).
+ *		(Basically a major rewrite).
+ *
+ *      Note: Routines labeled _TwoFish are private and should not be used
+ *      (or with extreme caution).
+ *
+ */
+
+#ifndef __TWOFISH_LIBRARY_HEADER__
+#define __TWOFISH_LIBRARY_HEADER__
+
+#ifndef FALSE
+#define FALSE	0
+#endif
+#ifndef TRUE
+#define TRUE	!FALSE
+#endif
+#ifndef bool
+#define bool	int
+#endif
+
+
+/* Constants */
+
+#define TwoFish_DEFAULT_PW		"SnortHas2FishEncryptionRoutines!" /* default password (not more than 32 chars) */
+#define TwoFish_MAGIC			"TwoFish"			/* to indentify a successful decryption */
+
+enum
+{	TwoFish_KEY_SIZE = 256,					/* Valid values: 64, 128, 192, 256 */
+											/* User 256, other key sizes have not been tested. */
+											/* (But should work. I substituted as much as */
+											/* I could with this define.) */
+	TwoFish_ROUNDS = 16,
+	TwoFish_BLOCK_SIZE = 16,				/* bytes in a data-block */
+	TwoFish_KEY_LENGTH = TwoFish_KEY_SIZE/8,	/* 32= 256-bit key */
+	TwoFish_TOTAL_SUBKEYS = 4+4+2*TwoFish_ROUNDS,
+	TwoFish_MAGIC_LEN = TwoFish_BLOCK_SIZE-8,
+	TwoFish_SK_BUMP = 0x01010101,
+	TwoFish_SK_ROTL = 9,
+	TwoFish_P_00 = 1,
+	TwoFish_P_01 = 0,
+	TwoFish_P_02 = 0,
+	TwoFish_P_03 = TwoFish_P_01 ^ 1,
+	TwoFish_P_04 = 1,
+	TwoFish_P_10 = 0,
+	TwoFish_P_11 = 0,
+	TwoFish_P_12 = 1,
+	TwoFish_P_13 = TwoFish_P_11 ^ 1,
+	TwoFish_P_14 = 0,
+	TwoFish_P_20 = 1,
+	TwoFish_P_21 = 1,
+	TwoFish_P_22 = 0,
+	TwoFish_P_23 = TwoFish_P_21 ^ 1,
+	TwoFish_P_24 = 0,
+	TwoFish_P_30 = 0,
+	TwoFish_P_31 = 1,
+	TwoFish_P_32 = 1,
+	TwoFish_P_33 = TwoFish_P_31 ^ 1,
+	TwoFish_P_34 = 1,
+	TwoFish_GF256_FDBK =   0x169,
+	TwoFish_GF256_FDBK_2 = 0x169 / 2,
+	TwoFish_GF256_FDBK_4 = 0x169 / 4,
+	TwoFish_RS_GF_FDBK = 0x14D,		/* field generator */
+	TwoFish_MDS_GF_FDBK = 0x169		/* primitive polynomial for GF(256) */
+};
+
+
+/* Global data structure for callers */
+
+typedef struct
+{	u_int32_t sBox[4 * 256];					/* Key dependent S-box */
+	u_int32_t subKeys[TwoFish_TOTAL_SUBKEYS];	/* Subkeys  */
+	u_int8_t key[TwoFish_KEY_LENGTH];			/* Encryption Key */
+	u_int8_t *output;							/* Pointer to output buffer */
+	u_int8_t qBlockPlain[TwoFish_BLOCK_SIZE];	/* Used by CBC */
+	u_int8_t qBlockCrypt[TwoFish_BLOCK_SIZE];
+	u_int8_t prevCipher[TwoFish_BLOCK_SIZE];
+	struct 				/* Header for crypt functions. Has to be at least one block long. */
+	{	u_int32_t salt;							/* Random salt in first block (will salt the rest through CBC) */
+		u_int8_t length[4];					/* The amount of data following the header */
+		u_int8_t magic[TwoFish_MAGIC_LEN];		/* Magic to identify successful decryption  */
+	}	header;
+	bool qBlockDefined;
+	bool dontflush;
+}	TWOFISH;
+
+#ifndef __TWOFISH_LIBRARY_SOURCE__
+
+extern bool TwoFish_srand;					/* if set to TRUE (default), first call of TwoFishInit will seed rand();  */
+											/* call of TwoFishInit */
+#endif
+
+
+/**** Public Functions ****/
+
+/*	TwoFish Initialization
+ *
+ *	This routine generates a global data structure for use with TwoFish,
+ *	initializes important values (such as subkeys, sBoxes), generates subkeys
+ *	and precomputes the MDS matrix if not already done.
+ *
+ *	Input:	User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!')
+ *
+ *  Output:	Pointer to TWOFISH structure. This data structure contains key dependent data.
+ *			This pointer is used with all other crypt functions.
+ */
+TWOFISH *TwoFishInit(char *userkey);
+
+
+/*	TwoFish Destroy
+ *
+ *	Nothing else but a free...
+ *
+ *	Input:	Pointer to the TwoFish structure.
+ *
+ */
+void TwoFishDestroy(TWOFISH *tfdata);
+
+
+/*	TwoFish Alloc
+ *
+ *	Allocates enough memory for the output buffer as required.
+ *
+ *	Input:	Length of the plaintext.
+ *			Boolean flag for BinHex Output.
+ *			Pointer to the TwoFish structure.
+ *
+ *	Output:	Returns a pointer to the memory allocated.
+ */
+void *TwoFishAlloc(unsigned long len,bool binhex,bool decrypt,TWOFISH *tfdata);
+
+
+/*	TwoFish Free
+ *
+ *	Free's the allocated buffer.
+ *
+ *	Input:	Pointer to the TwoFish structure
+ *
+ *	Output:	(none)
+ */
+void TwoFishFree(TWOFISH *tfdata);
+
+
+/*	TwoFish Set Output
+ *
+ *	If you want to allocate the output buffer yourself,
+ *	then you can set it with this function.
+ *
+ *	Input:	Pointer to your output buffer
+ *			Pointer to the TwoFish structure
+ *
+ *	Output:	(none)
+ */
+void TwoFishSetOutput(char *outp,TWOFISH *tfdata);
+
+
+/*	TwoFish Raw Encryption
+ *
+ *	Does not use header, but does use CBC (if more than one block has to be encrypted).
+ *
+ *	Input:	Pointer to the buffer of the plaintext to be encrypted.
+ *			Pointer to the buffer receiving the ciphertext.
+ *			The length of the plaintext buffer.
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes encrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishEncryptRaw(char *in,char *out,unsigned long len,TWOFISH *tfdata);
+
+/*	TwoFish Raw Decryption
+ *
+ *	Does not use header, but does use CBC (if more than one block has to be decrypted).
+ *
+ *	Input:	Pointer to the buffer of the ciphertext to be decrypted.
+ *			Pointer to the buffer receiving the plaintext.
+ *			The length of the ciphertext buffer (at least one cipher block).
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes decrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishDecryptRaw(char *in,char *out,unsigned long len,TWOFISH *tfdata);
+
+
+/*	TwoFish Encryption
+ *
+ *	Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ *  this routine will alloc the memory. In addition, it will include a small 'header'
+ *  containing the magic and some salt. That way the decrypt routine can check if the
+ *  packet got decrypted successfully, and return 0 instead of garbage.
+ *
+ *	Input:	Pointer to the buffer of the plaintext to be encrypted.
+ *			Pointer to the pointer to the buffer receiving the ciphertext.
+ *				The pointer either points to user allocated output buffer space, or to NULL, in which case
+ *				this routine will set the pointer to the buffer allocated through the struct.
+ *			The length of the plaintext buffer.
+ *				Can be -1 if the input is a null terminated string, in which case we'll count for you.
+ *			Boolean flag for BinHex Output (if used, output will be twice as large as input).
+ *				Note: BinHex conversion overwrites (converts) input buffer!
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes encrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishEncrypt(char *in,char **out,signed long len,bool binhex,TWOFISH *tfdata);
+
+
+/*	TwoFish Decryption
+ *
+ *	Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ *  this routine will alloc the memory. In addition, it will check the small 'header'
+ *  containing the magic. If magic does not match we return 0. Otherwise we return the
+ *  amount of bytes decrypted (should be the same as the length in the header).
+ *
+ *	Input:	Pointer to the buffer of the ciphertext to be decrypted.
+ *			Pointer to the pointer to the buffer receiving the plaintext.
+ *				The pointer either points to user allocated output buffer space, or to NULL, in which case
+ *				this routine will set the pointer to the buffer allocated through the struct.
+ *			The length of the ciphertext buffer.
+ *				Can be -1 if the input is a null terminated binhex string, in which case we'll count for you.
+ *			Boolean flag for BinHex Input (if used, plaintext will be half as large as input).
+ *				Note: BinHex conversion overwrites (converts) input buffer!
+ *			The TwoFish structure.
+ *
+ *	Output:	The amount of bytes decrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishDecrypt(char *in,char **out,signed long len,bool binhex,TWOFISH *tfdata);
+
+
+/**** Private Functions ****/
+
+u_int8_t TwoFish__b(u_int32_t x,int n);
+void _TwoFish_BinHex(u_int8_t *buf,unsigned long len,bool bintohex);
+unsigned long _TwoFish_CryptRawCBC(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata);
+unsigned long _TwoFish_CryptRaw16(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata);
+unsigned long _TwoFish_CryptRaw(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata);
+void _TwoFish_PrecomputeMDSmatrix(void);
+void _TwoFish_MakeSubKeys(TWOFISH *tfdata);
+void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata);
+void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata);
+void _TwoFish_ResetCBC(TWOFISH *tfdata);
+void _TwoFish_FlushOutput(u_int8_t *b,unsigned long len,TWOFISH *tfdata);
+void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,unsigned long size,int decrypt,TWOFISH *tfdata);
+void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata);
+u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1);
+u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32);
+u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x);
+u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x);
+u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R);
+
+
+#endif

Index: snort-2.8.6/src/plugin_enum.h
===================================================================
--- snort-2.8.6/src/plugin_enum.h	(Revision 1)
+++ snort-2.8.6/src/plugin_enum.h	(Revision 3)
@@ -60,6 +60,7 @@
     PLUGIN_URILEN_CHECK,
     PLUGIN_DYNAMIC,
     PLUGIN_FLOWBIT,
+    PLUGIN_FWSAM,
     PLUGIN_MAX  /* sentinel value */
 };
 
Index: snort-2.8.6/src/fatal.h
===================================================================
--- snort-2.8.6/src/fatal.h	(Revision 0)
+++ snort-2.8.6/src/fatal.h	(Revision 3)
@@ -0,0 +1,40 @@
+/* $Id$ */
+/*
+** Copyright (C) 2002-2008 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation.  You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FATAL_H__
+#define __FATAL_H__
+
+
+/*
+ * in debugging mode print out the filename and the line number where the
+ * failure have occured
+ */
+
+
+#ifdef DEBUG
+	#define	FATAL(msg) 	{ printf("%s:%d: ", __FILE__, __LINE__); FatalError( (char *) msg); }
+#else
+	#define	FATAL(msg)	FatalError( (char *) msg)
+#endif
+
+
+
+#endif	/* __FATAL_H__ */

Index: snort-2.8.6/src/output-plugins/spo_alert_fwsam.c
===================================================================
--- snort-2.8.6/src/output-plugins/spo_alert_fwsam.c	(Revision 0)
+++ snort-2.8.6/src/output-plugins/spo_alert_fwsam.c	(Revision 3)
@@ -0,0 +1,1380 @@
+/* $id: snortpatchb,v 1.2 2002/10/26 03:32:35 fknobbe Exp $
+**
+** spo_alert_fwsam.c
+**
+** Copyright (c) 2001-2004 Frank Knobbe <frank@knobbe.us>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Purpose:
+ *
+ * This module sends alerts to a remote service on a host running SnortSam
+ * (the agent) which will block the intruding IP address on a variety of
+ * host and network firewalls.
+ *
+ * SnortSam also performs checks against a white-list of never-to-be-blocked IP addresses,
+ * can override block durations (for example for known proxies), and can detect attack conditions
+ * where too many blocks are received within a defined interval. If an attack is detected
+ * it will unblock the last x blocks and wait for the attack to end.
+ *
+ * See the SnortSam documentation for more information.
+ *
+ *
+ * Output Plugin Parameters:
+ ***************************
+ *
+ * output alert_fwsam: <SnortSam Station>:<port>/<key>
+ *
+ *	<FW Mgmt Station>:	The IP address or host name of the host running SnortSam.
+ *	<port>:			The port the remote SnortSam service listens on (default 898).
+ *	<key>:			The key used for authentication (encryption really)
+ *				of the communication to the remote service.
+ *
+ * Examples:
+ *
+ * output alert_fwsam: snortsambox/idspassword
+ * output alert_fwsam: fw1.domain.tld:898/mykey
+ * output alert_fwsam: 192.168.0.1/borderfw  192.168.1.254/wanfw
+ *
+ *
+ * Rule Options:
+ ***************
+ *
+ * fwsam:	who[how],time;
+ *
+ *  who: src, source, dst, dest, destination
+ *			IP address to be blocked according to snort rule (some rules
+ *			are reversed, i.e. homenet -> any [and you want to block any]).
+ *          src denotes IP to the left of -> and dst denotes IP to the right
+ *
+ *  how: Optional. In, out, src, dest, either, both, this, conn, connection
+ *			Tells FW-1 to block packets INcoming from host, OUTgoing to host,
+ *			EITHERway, or only THIS connection (IP/Service pair).
+ *			See 'fw sam' for more information. May be ignored by other plugins.
+ *
+ * time: Duration of block in seconds. (Accepts 'days', 'months', 'weeks',
+ *		 'years', 'minutes', 'seconds', 'hours'. Alternatively, a value of
+ *		 0, or the keyword PERManent, INFinite, or ALWAYS, will block the
+ *		 host permanently. Be careful with this!
+ *			Tells FW-1 (and others) how long to inhibit packets from the host.
+ *
+ * Examples:
+ *
+ * fwsam:  src[either],15min;
+ *     or  dst[in], 2 days 4 hours
+ *     or  src, 1 hour
+ *
+ *         (default: src[either],5min)
+ *
+ *
+ * Effect:
+ *
+ * Alerts are sent to the remote SnortSam services on Firewall-1 Management Stations
+ * or other hosts running SnortSam (as required for Cisco Routers and PIX).
+ * The remote services will invoke the SAM configuration via the fw sam
+ * command line, or by sending a packet to the SAM port 18183, or by using the official
+ * OPSEC API calls, or by telnetting into Cisco routers or PIX firewalls.
+ * The communication over the network is encrypted using two-fish.
+ * (Implementation ripped from CryptCat by Farm9 with permission.)
+ *
+ * Future Plans:
+ *
+ * - Custom alert trigger per rule (x alerts in y secs) --> Seems to exist in Snort 1.9 now.
+ * - Enable/Allow tagged fwsam: arguments to provide different values to
+ *        different stations.  --> Seems to be accomplished with custom rule-types
+ *
+ *
+ * Comments:
+ *
+ * It seem that above wishes can be implemented with todays setup. Feedback concerning
+ * these is greatly appreciated.
+ *
+*/
+
+
+#include "spo_alert_fwsam.h"
+#include "twofish.h"
+/* external globals from rules.c  */
+extern char *file_name;
+extern int file_line;
+extern OptTreeNode *otn_tmp;
+extern char *snort_conf_dir; /* extern PV pv; */
+
+
+/* my globals  */
+
+FWsamList *FWsamStationList=NULL;			/* Global (for all alert-types) list of snortsam stations */
+FWsamOptions *FWsamOptionField=NULL;
+unsigned long FWsamMaxOptions=0;
+
+
+/*
+ * Function: AlertFWsamSetup()
+ *
+ * Purpose: Registers the output plugin keyword and initialization
+ *          function into the output plugin list.  This is the function that
+ *          gets called from InitOutputPlugins() in plugbase.c.
+ *			It also registers itself as a plugin in order to parse every rule
+ *			and to set the appropiate flags from fwsam: option.
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+*/
+void AlertFWsamSetup(void)
+{
+    /* link the preprocessor keyword to the init function in
+       the preproc list */
+    RegisterOutputPlugin("alert_fwsam", OUTPUT_TYPE_FLAG__ALERT, AlertFWsamInit);
+    RegisterRuleOption("fwsam", AlertFWsamOptionInit, NULL, OPT_TYPE_ACTION, NULL);
+
+#ifdef FWSAMDEBUG   /* This allows debugging of fwsam only */
+    LogMessage("DEBUG => [Alert_FWsam](AlertFWsamSetup) Output plugin is plugged in...\n");
+#endif
+}
+
+
+/*	This function checks if a given snortsam station is already in
+ *	a given list.
+*/
+int FWsamStationExists(FWsamStation *who,FWsamList *list)
+{
+    while(list)
+    {
+        if(list->station) {
+//			if(	who->stationip.s_addr==list->station->stationip.s_addr &&
+            if(IP_EQUALITY(&who->stationip, &list->station->stationip) &&
+            who->stationport==list->station->stationport)
+            return TRUE;
+        }
+        list=list->next;
+    }
+    return FALSE;
+}
+
+/*
+ * Function: AlertFWsamInit(char *args)
+ *
+ * Purpose: Calls the argument parsing function, performs final setup on data
+ *          structs, links the preproc function into the function list.
+ *
+ * Arguments: args => ptr to argument string
+ *
+ * Returns: void function
+ *
+*/
+void AlertFWsamInit(char *args)
+{	char *ap;
+	unsigned long statip,cnt,again,i;
+	char *stathost,*statport,*statpass;
+	FWsamStation *station;
+	FWsamList *fwsamlist=NULL;	/* alert-type dependent list of snortsam stations  */
+	FWsamList *listp,*newlistp;
+	struct hostent *hoste;
+	char buf[1024]="";
+	FILE *fp;
+	FWsamOptions tempopt;
+
+#ifdef FWSAMDEBUG
+	unsigned long hostcnt=0;
+
+
+
+    LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Output plugin initializing...\n");
+#endif
+
+    /* pv.alert_plugin_active = 1; */
+
+    /* parse the argument list from the rules file */
+
+	if(args == NULL)
+		FatalError("ERROR %s (%d) => [Alert_FWsam](AlertFWsamInit) No arguments to alert_fwsam preprocessor!\n", file_name, file_line);
+
+	if(!FWsamOptionField && !FWsamMaxOptions)
+	{	strncpy(buf,snort_conf_dir,sizeof(buf)-1);
+		strncpy(buf+strlen(buf),SID_MAPFILE,sizeof(buf)-strlen(buf)-1);
+#ifdef FWSAMDEBUG
+		LogMessage("DEBUG => [Alert_FWsam](AlertFWsamSetup) Using file: %s\n",buf);
+#endif
+		fp=fopen(buf,"rt");
+		if(!fp)
+		{	strncpy(buf,snort_conf_dir,sizeof(buf)-1);
+			strncpy(buf+strlen(buf),SID_ALT_MAPFILE,sizeof(buf)-strlen(buf)-1);
+			fp=fopen(buf,"rt");
+		}
+		if(fp)  /* Check for presence of map file and read those in, sorted. */
+		{   LogMessage("INFO => [Alert_FWsam](AlertFWsamSetup) Using sid-map file: %s\n",buf);
+
+			while(FWsamReadLine(buf,sizeof(buf),fp))
+				if(*buf)
+					FWsamMaxOptions++;
+			if(FWsamMaxOptions)
+			{   if((FWsamOptionField=(FWsamOptions *)malloc(sizeof(FWsamOptions)*FWsamMaxOptions))==NULL)
+					FatalError("ERROR => [Alert_FWsam](AlertFWsamSetup) malloc failed for OptionField!\n");
+				fseek(fp,0,SEEK_SET);
+				for(cnt=0;cnt<FWsamMaxOptions;)
+				{	FWsamReadLine(buf,sizeof(buf),fp);
+					if(*buf)
+						FWsamParseLine(&(FWsamOptionField[cnt++]),buf);
+				}
+				if(FWsamMaxOptions>1)
+				{	for(again=TRUE,cnt=FWsamMaxOptions-1;cnt>=1 && again;cnt--)
+					{	for(again=FALSE,i=0;i<cnt;i++)
+						{	if(FWsamOptionField[i].sid>FWsamOptionField[i+1].sid)
+							{	memcpy(&tempopt,&(FWsamOptionField[i]),sizeof(FWsamOptions));
+								memcpy(&(FWsamOptionField[i]),&(FWsamOptionField[i+1]),sizeof(FWsamOptions));
+								memcpy(&(FWsamOptionField[i+1]),&tempopt,sizeof(FWsamOptions));
+								again=TRUE;
+							}
+						}
+					}
+				}
+			}
+			else
+				FWsamMaxOptions=1;
+			fclose(fp);
+		}
+		else
+			FWsamMaxOptions=1;
+	}
+
+
+	ap=args; /* start at the beginning of the argument */
+	while(*ap && isspace(*ap)) ap++;
+	while(*ap)
+	{	stathost=ap; /* first argument should be host */
+		statport=NULL;
+		statpass=NULL;
+		while(*ap && *ap!=':' && *ap!='/' && !isspace(*ap)) ap++; /* find token */
+		switch(*ap)
+		{	case ':':	*ap++=0; /* grab the port */
+						statport=ap;
+						while(*ap && *ap!='/' && !isspace(*ap)) ap++;
+						if(*ap!='/')
+							break;
+			case '/':	*ap++=0; /* grab the key */
+						statpass=ap;
+						while(*ap && !isspace(*ap)) ap++;
+			default:	break;
+		}
+		if(*ap)
+		{	*ap++=0;
+			while(isspace(*ap)) ap++;
+		}
+		/* now we have the first host with port and password (key) */
+		/* next we check for valid/blank password/port */
+		if(statpass!=NULL)
+			if(!*statpass)
+				statpass=NULL;
+		if(statport!=NULL)
+			if(!*statport)
+				statport=NULL;
+		statip=0;
+		/* now we check if a valid host was specified */
+		if(inet_addr(stathost)==INADDR_NONE)
+		{	hoste=gethostbyname(stathost);
+			if (!hoste)
+				LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWsamInit) Unable to resolve host '%s'!\n",file_name,file_line,stathost);
+			else
+				statip=*(unsigned long *)hoste->h_addr;
+		}
+		else
+		{	statip=inet_addr(stathost);
+			if(!statip)
+				LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWsamInit) Invalid host address '%s'!\n",file_name,file_line,stathost);
+		}
+		if(statip)
+		{	/* groovie, a valid host. Let's alloc and assemble the structure for it. */
+			if((station=(FWsamStation *)malloc(sizeof(FWsamStation)))==NULL)
+				FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for station!\n");
+
+//			station->stationip.s_addr=statip; /* the IP address */
+			station->stationip.ip32[0] = statip; /* the IP address */
+			if(statport!=NULL && atoi(statport)>0) /* if the user specified one */
+				station->stationport=atoi(statport); /* use users setting */
+			else
+				station->stationport=FWSAM_DEFAULTPORT; /* set the default port */
+
+			if(statpass!=NULL) /* if specified by user */
+				strncpy(station->stationkey,statpass,TwoFish_KEY_LENGTH); /* use defined key */
+			else
+				station->stationkey[0]=0;
+			station->stationkey[TwoFish_KEY_LENGTH]=0; /* make sure it's terminated. (damn strncpy...) */
+
+			strcpy(station->initialkey,station->stationkey);
+			station->stationfish=TwoFishInit(station->stationkey);
+
+			station->localsocketaddr.sin_port=htons(0); /* let's use dynamic ports for now */
+			station->localsocketaddr.sin_addr.s_addr=0;
+			station->localsocketaddr.sin_family=AF_INET;
+			station->stationsocketaddr.sin_port=htons(station->stationport);
+			//station->stationsocketaddr.sin_addr=station->stationip;
+			station->stationsocketaddr.sin_addr.s_addr=station->stationip.ip32[0];
+			station->stationsocketaddr.sin_family=AF_INET; /* load all socket crap and keep for later */
+
+			do
+				station->myseqno=rand(); /* the seqno this host will use */
+			while(station->myseqno<20 || station->myseqno>65500);
+			station->mykeymod[0]=rand();
+			station->mykeymod[1]=rand();
+			station->mykeymod[2]=rand();
+			station->mykeymod[3]=rand();
+			station->stationseqno=0;				/* peer hasn't answered yet. */
+
+
+			if(!FWsamStationExists(station,FWsamStationList))	/* If we don't have the station already in global list....*/
+			{	if(FWsamCheckIn(station))			/* ...and we can talk to the agent...  */
+				{	if((newlistp=(FWsamList *)malloc(sizeof(FWsamList)))==NULL)
+						FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for global newlistp!\n");
+					newlistp->station=station;
+					newlistp->next=NULL;
+
+					if(!FWsamStationList)				/* ... add it to the global list/ */
+						FWsamStationList=newlistp;
+					else
+					{	listp=FWsamStationList;
+						while(listp->next)
+							listp=listp->next;
+						listp->next=newlistp;
+					}
+				}
+				else
+				{	TwoFishDestroy(station->stationfish); /* if not, we trash it. */
+					free(station);
+					station=NULL;
+				}
+			}
+#ifdef FWSAMDEBUG
+			else
+				LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Host %s:%i already in global list, skipping CheckIn.\n", sfip_ntoa(&station->stationip),station->stationport);
+#endif
+
+			if(station)
+			{	if(!FWsamStationExists(station,fwsamlist))	/* If we don't have the station already in local list....*/
+				{	if((newlistp=(FWsamList *)malloc(sizeof(FWsamList)))==NULL)
+						FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for local newlistp!\n");
+					newlistp->station=station;
+					newlistp->next=NULL;
+
+					if(!fwsamlist)				/* ... add it to the local list/ */
+						fwsamlist=newlistp;
+					else
+					{	listp=fwsamlist;
+						while(listp->next)
+							listp=listp->next;
+						listp->next=newlistp;
+					}
+				}
+
+#ifdef FWSAMDEBUG
+				else
+					LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Host %s:%i already in local list, skipping.\n",sfip_ntoa(&station->stationip),station->stationport);
+				LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) #%i: Host %s [%s] port %i password %s\n",++hostcnt,stathost,sfip_ntoa(&station->stationip),station->stationport,station->stationkey);
+#endif
+			}
+
+		}
+	}	/* next one */
+
+#ifdef FWSAMDEBUG
+    LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Linking fwsam alert function to call list...\n");
+#endif
+
+    /* Set the preprocessor function into the function list */
+    AddFuncToOutputList(AlertFWsam, OUTPUT_TYPE_FLAG__ALERT, fwsamlist);
+    AddFuncToCleanExitList(AlertFWsamCleanExitFunc, fwsamlist);
+    AddFuncToRestartList(AlertFWsamRestartFunc, fwsamlist);
+}
+
+
+/*	This routine reads in a str from a file, snips white-spaces
+ *	off the front and back, removes comments, and pretties the
+ *	string. Returns true or false if a line was read or not.
+*/
+int FWsamReadLine(char *buf,unsigned long bufsize,FILE *fp)
+{	char *p;
+
+	if(fgets(buf,bufsize-1,fp))
+	{	buf[bufsize-1]=0;
+
+#ifdef FWSAMDEBUG_off
+		LogMessage("DEBUG => [Alert_FWsam](AlertFWsamReadLine) Line: %s\n",buf);
+#endif
+
+		p=buf;
+		while(isspace(*p))
+		  p++;
+		if(p>buf);
+			strcpy(buf,p);
+		if(*buf)
+		{	p=buf+strlen(buf)-1;	/* remove leading and trailing spaces */
+			while(isspace(*p))
+				*p-- =0;
+		}
+		p=buf;
+		if(*p=='#' || *p==';')
+			*p=0;
+		else
+			p++;
+		while(*p)					/* remove inline comments (except escaped #'s and ;'s) */
+		{	if(*p=='#' || *p==';')
+			{	if(*(p-1)=='\\')
+					strcpy(p-1,p);
+				else
+					*p=0;
+			}
+			else
+				p++;
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+
+/* Parses the duration of the argument, recognizing minutes, hours, etc..
+*/
+unsigned long FWsamParseDuration(char *p)
+{	unsigned long dur=0,tdu;
+	char *tok,c1,c2;
+
+	while(*p)
+	{	tok=p;
+		while(*p && isdigit(*p))
+			p++;
+		if(*p)
+		{	c1=tolower(*p);
+			*p=0;
+			p++;
+			if(*p && !isdigit(*p))
+			{	c2=tolower(*p++);
+				while(*p && !isdigit(*p))
+					p++;
+			}
+			else
+				c2=0;
+			tdu=atol(tok);
+			switch(c1)
+			{	case 'm':	if(c2=='o')				/* month */
+								tdu*=(60*60*24*30);	/* use 30 days */
+							else
+								tdu*=60;			/* minutes */
+				case 's':	break;					/* seconds */
+				case 'h':	tdu*=(60*60);			/* hours */
+							break;
+				case 'd':	tdu*=(60*60*24);		/* days */
+							break;
+				case 'w':	tdu*=(60*60*24*7);		/* week */
+							break;
+				case 'y':	tdu*=(60*60*24*365);	/* year */
+							break;
+			}
+			dur+=tdu;
+		}
+		else
+			dur+=atol(tok);
+	}
+
+	return dur;
+}
+
+
+/*  This routine parses an option line. It is called by FWsamParseLine,
+ *  which parses the sid-block.map file, and also by AlertFWsamOptionInit,
+ *  which is called by Snort when processing fwsam: options in rules.
+ *  It returns TRUE it there is a possible option problem, otherwise FALSE.
+*/
+int FWsamParseOption(FWsamOptions *optp,char *ap)
+{   int possprob=FALSE;
+
+	/* set defaults */
+
+	optp->duration=300;					/* default of 5 minute block */
+	optp->how=FWSAM_HOW_INOUT;			/* inbound and outbound block */
+	optp->who=FWSAM_WHO_SRC;			/* the source  */
+    optp->loglevel=FWSAM_LOG_LONGALERT; /* the log level default */
+	/* parse the fwsam keywords */
+
+#ifdef FWSAMDEBUG
+	LogMessage("DEBUG => [Alert_FWsam](AlertFWamOptionInit) Parse Options Args: %s\n",ap);
+#endif
+
+	if(*ap)		/* should be dst/src (the WHO) or duration */
+	{	if(isdigit(*ap))
+			optp->duration=FWsamParseDuration(ap);
+		else
+		{	switch(*ap)			/* yeah, we're lazy and check only the first character */
+			{	case 'p':	;								/* permanent, perm */
+				case 'f':	;								/* forever */
+				case 'i':	optp->duration=0;				/* infinite, inf */
+							break;
+				case 'd':	optp->who=FWSAM_WHO_DST;		/* destination, dest, dst */
+							break;
+				case 's':	optp->who=FWSAM_WHO_SRC;		/* source, src */
+							break;
+				default:	possprob=TRUE;
+			}
+			while(*ap && *ap!=',' && *ap!='[')
+				ap++;
+			if(*ap=='[')
+			{	ap++;		/* now we have the HOW */
+				switch(*ap)
+				{	case 'i':	;							/* in */
+					case 's':	optp->how=FWSAM_HOW_IN;		/* source, src */
+								break;
+					case 'o':	;							/* out */
+					case 'd':	optp->how=FWSAM_HOW_OUT;	/* destination, dest, dst */
+								break;
+					case 'b':	;							/* both */
+					case 'e':	optp->how=FWSAM_HOW_INOUT;	/* either */
+								break;
+					case 't':	;							/* this */
+					case 'c':	optp->how=FWSAM_HOW_THIS;	/* connection, conn */
+								break;
+					default:	possprob=TRUE;
+				}
+				while(*ap && *ap!=',')
+					ap++;
+			}
+			if(*ap==',')
+			{	ap++;
+				if(isdigit(*ap))  /* and figure out how long to block */
+					optp->duration=FWsamParseDuration(ap);
+				else if(*ap=='p' || *ap=='f' || *ap=='i')
+					optp->duration=0;
+				else
+					possprob=TRUE;
+			}
+			else if(!*ap)
+				possprob=TRUE;
+		}
+	}
+	else
+		possprob=TRUE;
+
+	return possprob;
+}
+
+
+/*	This goes through the lines of sid-block.map and sets the
+ *	options for fwsam if the file is being used.
+*/
+void FWsamParseLine(FWsamOptions *optp,char *buf)
+{   char *ap;
+
+	ap=buf; /* start at the beginning of the argument */
+
+	while(*ap)
+	{	if(isspace(*ap))		/* normalize spaces (tabs into space, etc) */
+			*ap=' ';
+		if(isupper(*ap))		/* and set to lower case */
+			*ap=tolower(*ap);
+		ap++;
+	}
+	while((ap=strrchr(buf,' '))!=NULL)	/* remove spaces */
+		strcpy(ap,ap+1);
+
+	ap=buf;
+	if(*ap)
+	{	while(*ap && *ap!=':' && *ap!='|')
+			ap++;
+		*ap++ =0;
+		while(*ap && (*ap==':' || *ap=='|'))
+			ap++;
+
+		optp->sid=(unsigned long)atol(buf);
+
+		if(FWsamParseOption(optp,ap))
+			LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWamOptionInit) Possible option problem. Using %s[%s],%lu.\n",file_name,file_line,(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration);
+	}
+	else
+		optp->sid=0;
+}
+
+
+
+/*
+ * Function: AlertFWsamOptionInit(char *data, OptTreeNode *otn, int protocol)
+ *
+ * Purpose: Parses each rule and sets the option flags in the tree.
+ *
+ * Arguments: args => ptr to argument string
+ *
+ * Returns: void function
+ *
+*/
+void AlertFWsamOptionInit(char *args,OptTreeNode *otn,int protocol)
+{
+    FWsamOptions *optp;
+	char *ap;
+
+
+#ifdef FWSAMDEBUG
+    LogMessage("DEBUG => [Alert_FWsam](AlertFWamOptionInit) FWsamOptionInit is parsing...\n");
+#endif
+
+    if((optp=(FWsamOptions *)malloc(sizeof(FWsamOptions)))==NULL)
+		FatalError("ERROR => [Alert_FWsam](AlertFWamOptionInit) malloc failed for opt!\n");
+
+
+	ap=args; /* start at the beginning of the argument */
+
+	while(*ap)
+	{	if(isspace(*ap))		/* normalize spaces (tabs into space, etc) */
+			*ap=' ';
+		if(isupper(*ap))		/* and set to lower case */
+			*ap=tolower(*ap);
+		ap++;
+	}
+	while((ap=strrchr(args,' '))!=NULL)	/* remove spaces */
+		strcpy(ap,ap+1);
+
+
+	if(FWsamParseOption(optp,args))
+		LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWamOptionInit) Possible option problem. Using %s[%s],%lu.\n",file_name,file_line,(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration);
+
+	otn->ds_list[PLUGIN_FWSAM]=(FWsamOptions *)optp;
+}
+
+
+/* Generates a new encryption key for TwoFish based on seq numbers and a random that
+ * the SnortSam agents send on checkin (in protocol)
+*/
+void FWsamNewStationKey(FWsamStation *station,FWsamPacket *packet)
+{
+    //unsigned char newkey[TwoFish_KEY_LENGTH+2];
+    char newkey[TwoFish_KEY_LENGTH+2];
+	int i;
+
+	newkey[0]=packet->snortseqno[0];		/* current snort seq # (which both know) */
+	newkey[1]=packet->snortseqno[1];
+	newkey[2]=packet->fwseqno[0];			/* current SnortSam seq # (which both know) */
+	newkey[3]=packet->fwseqno[1];
+	newkey[4]=packet->protocol[0];		/* the random SnortSam chose */
+	newkey[5]=packet->protocol[1];
+
+	strncpy(newkey+6,station->stationkey,TwoFish_KEY_LENGTH-6); /* append old key */
+	newkey[TwoFish_KEY_LENGTH]=0;
+
+	newkey[0]^=station->mykeymod[0];		/* modify key with key modifiers which were */
+	newkey[1]^=station->mykeymod[1];		/* exchanged during the check-in handshake. */
+	newkey[2]^=station->mykeymod[2];
+	newkey[3]^=station->mykeymod[3];
+	newkey[4]^=station->fwkeymod[0];
+	newkey[5]^=station->fwkeymod[1];
+	newkey[6]^=station->fwkeymod[2];
+	newkey[7]^=station->fwkeymod[3];
+
+	for(i=0;i<=7;i++)
+		if(newkey[i]==0)
+			newkey[i]++;
+
+	strcpy(station->stationkey,newkey);
+	TwoFishDestroy(station->stationfish);
+	station->stationfish=TwoFishInit(newkey);
+}
+
+
+/*	This routine will search the option list as defined
+ *	by the sid-block.map file and return a pointer
+ *	to the matching record.
+*/
+FWsamOptions *FWsamGetOption(unsigned long sid)
+{	signed long i,step,diff,o,o2;
+
+#ifdef FWSAM_FANCYFETCH       /* Fancy-fetch jumps in decreasing n/2 steps and takes much less lookups */
+	o=o2= -1;
+	i=step=FWsamMaxOptions>>1;
+	while(i>=0 && i<FWsamMaxOptions && i!=o2)
+	{	diff=sid-FWsamOptionField[i].sid;
+		if(!diff)
+			return &(FWsamOptionField[i]);
+		if(step>1)
+			step=step>>1;
+		o2=o;
+		o=i;
+		if(diff>0)
+			i+=step;
+		else
+			i-=step;
+	}
+#else						/* This is just a sequential list lookup */
+	for(i=0;i<FWsamMaxOptions;i++)
+		if(FWsamOptionField[i].sid==sid)
+			return &(FWsamOptionField[i]);
+#endif
+	return NULL;
+}
+
+
+/****************************************************************************
+ *
+ * Function: AlertFWsam(Packet *, char *)
+ *
+ * Purpose: Send the current alert to a remote module on a FW-1 mgmt station
+ *
+ * Arguments: p => pointer to the packet data struct
+ *            msg => the message to print in the alert
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void AlertFWsam(Packet *p, char *msg, void *arg, Event *event)
+{	FWsamOptions *optp;
+	FWsamPacket sampacket;
+	FWsamStation *station=NULL;
+	FWsamList *fwsamlist;
+	SOCKET stationsocket;
+	int i,len,deletestation,stationtry=0;
+	//unsigned char *encbuf,*decbuf;
+    char *encbuf,*decbuf;
+	static unsigned long lastbsip[FWSAM_REPET_BLOCKS],lastbdip[FWSAM_REPET_BLOCKS],
+						 lastbduration[FWSAM_REPET_BLOCKS],lastbtime[FWSAM_REPET_BLOCKS];
+	static unsigned short lastbsp[FWSAM_REPET_BLOCKS],lastbdp[FWSAM_REPET_BLOCKS],
+						  lastbproto[FWSAM_REPET_BLOCKS],lastbpointer;
+	static unsigned char lastbmode[FWSAM_REPET_BLOCKS];
+	static unsigned long btime=0;
+
+
+	if(otn_tmp==NULL)
+    {
+#ifdef FWSAMDEBUG
+        LogMessage("DEBUG => [Alert_FWsam] NULL otn_tmp!\n");
+#endif
+        return;
+    }
+    if(p == NULL)
+    {
+#ifdef FWSAMDEBUG
+        LogMessage("DEBUG => [Alert_FWsam] NULL packet!\n");
+#endif
+        return;
+    }
+    if(arg == NULL)
+    {
+#ifdef FWSAMDEBUG
+        LogMessage("DEBUG => [Alert_FWsam] NULL arg!\n");
+#endif
+        return;
+    }
+
+    /* SnortSam does no IPv6 */
+    if (!IS_IP4(p)) {
+#ifdef FWSAMDEBUG
+        LogMessage("DEBUG => [Alert_FWsam] not acting on non-IP4 packet!\n");
+#endif
+        return;
+    }
+
+	optp=NULL;
+
+	if(FWsamOptionField)            /* If using the file (field present), let's use that */
+		optp=FWsamGetOption(event->sig_id);
+
+	if(!optp)                       /* If file not present, check if an fwsam option was defined on the triggering rule */
+		optp=otn_tmp->ds_list[PLUGIN_FWSAM];
+
+	if(optp)	/* if options specified for this rule */
+	{	if(!btime)			/* if this is the first time this function is */
+		{	for(i=0;i<FWSAM_REPET_BLOCKS;i++)	/*  called, reset the time and protocol to 0. */
+			{	lastbproto[i]=0;
+				lastbtime[i]=0;
+			}
+		}
+
+		fwsamlist=(FWsamList *)arg;
+
+#ifdef FWSAMDEBUG
+		LogMessage("DEBUG => [Alert_FWsam] Alert -> Msg=\"%s\"\n",msg);
+
+		LogMessage("DEBUG => [Alert_FWsam] Alert -> Option: %s[%s],%lu.\n",(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration);
+#endif
+
+		len=TRUE;
+		btime=(unsigned long)time(NULL);	/* get current time */
+		/* This is a cheap check to see if the blocking request matches any of the previous requests. */
+		for(i=0;i<FWSAM_REPET_BLOCKS && len;i++)
+		{	if( ((optp->how==FWSAM_HOW_THIS)?	/* if blocking mode SERVICE, check for src and dst	  */
+				( lastbsip[i]==p->iph->ip_src.s_addr && lastbdip[i]==p->iph->ip_dst.s_addr &&lastbproto[i]==p->iph->ip_proto &&
+				  ((p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP)? /* check port only of TCP or UDP */
+/*					((optp->who==FWSAM_WHO_SRC)?(lastbsp[i]==p->sp):(lastbdp[i]==p->dp)):TRUE) ): */
+					lastbdp[i]==p->dp:TRUE) ):
+				((optp->who==FWSAM_WHO_SRC)?(lastbsip[i]==p->iph->ip_src.s_addr):(lastbdip[i]==p->iph->ip_dst.s_addr))) && /* otherwise if we block source, only compare source. Same for dest. */
+				lastbduration[i]==optp->duration &&
+				(lastbmode[i]&(FWSAM_HOW|FWSAM_WHO))==(optp->how|optp->who) &&
+				(btime-lastbtime[i]<((optp->duration>FWSAM_REPET_TIME)?FWSAM_REPET_TIME:optp->duration)))
+			{	len=FALSE;		/* If so, we don't need to block again. */
+			}
+		}
+		if(len)
+		{	if(++lastbpointer>=FWSAM_REPET_BLOCKS)		/* increase repetitive check pointer */
+				lastbpointer=0;
+			lastbsip[lastbpointer]=p->iph->ip_src.s_addr;		/* and note packet details */
+			lastbdip[lastbpointer]=p->iph->ip_dst.s_addr;
+			lastbduration[lastbpointer]=optp->duration;
+			lastbmode[lastbpointer]=optp->how|optp->who|optp->loglevel;
+			lastbproto[lastbpointer]=p->iph->ip_proto;
+			if(p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP)
+			{	lastbsp[lastbpointer]=p->sp;					/* set ports if TCP or UDP */
+				lastbdp[lastbpointer]=p->dp;
+			}
+			lastbtime[lastbpointer]=btime;
+
+
+			while(fwsamlist!=NULL)
+			{	station=fwsamlist->station;
+				//if(station->stationip.s_addr)
+				if(station->stationip.ip32[0])
+				{	deletestation=FALSE;
+					stationtry++;				/* first try */
+					/* create a socket for the station */
+					stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+					if(stationsocket==INVALID_SOCKET)
+						FatalError("ERROR => [Alert_FWsam] Funky socket error (socket)!\n");
+					if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr)))
+						FatalError("ERROR => [Alert_FWsam] Could not bind socket!\n");
+
+					/* let's connect to the agent */
+					if(connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr)))
+					{
+						LogMessage("WARNING => [Alert_FWsam] Could not send block to host %s. Will try later.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+						closesocket(stationsocket);
+#else
+						close(stationsocket);
+#endif
+						stationtry=0;
+					}
+					else
+					{
+#ifdef FWSAMDEBUG
+						LogMessage("DEBUG => [Alert_FWsam] Connected to host %s.\n",sfip_ntoa(&station->stationip));
+#endif
+						/* now build the packet */
+						station->myseqno+=station->stationseqno; /* increase my seqno by adding agent seq no */
+						sampacket.endiancheck=1;						/* This is an endian indicator for Snortsam */
+						sampacket.snortseqno[0]=(char)station->myseqno;
+						sampacket.snortseqno[1]=(char)(station->myseqno>>8);
+						sampacket.fwseqno[0]=(char)station->stationseqno;/* fill station seqno */
+						sampacket.fwseqno[1]=(char)(station->stationseqno>>8);
+						sampacket.status=FWSAM_STATUS_BLOCK;			/* set block mode */
+						sampacket.version=FWSAM_PACKETVERSION;			/* set packet version */
+						sampacket.duration[0]=(char)optp->duration;		/* set duration */
+						sampacket.duration[1]=(char)(optp->duration>>8);
+						sampacket.duration[2]=(char)(optp->duration>>16);
+						sampacket.duration[3]=(char)(optp->duration>>24);
+						sampacket.fwmode=optp->how|optp->who|optp->loglevel; /* set the mode */
+						sampacket.dstip[0]=(char)p->iph->ip_dst.s_addr; /* destination IP */
+						sampacket.dstip[1]=(char)(p->iph->ip_dst.s_addr>>8);
+						sampacket.dstip[2]=(char)(p->iph->ip_dst.s_addr>>16);
+						sampacket.dstip[3]=(char)(p->iph->ip_dst.s_addr>>24);
+						sampacket.srcip[0]=(char)p->iph->ip_src.s_addr;	/* source IP */
+						sampacket.srcip[1]=(char)(p->iph->ip_src.s_addr>>8);
+						sampacket.srcip[2]=(char)(p->iph->ip_src.s_addr>>16);
+						sampacket.srcip[3]=(char)(p->iph->ip_src.s_addr>>24);
+						sampacket.protocol[0]=(char)p->iph->ip_proto;	/* protocol */
+						sampacket.protocol[1]=(char)(p->iph->ip_proto>>8);/* protocol */
+
+						if(p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP)
+						{	sampacket.srcport[0]=(char)p->sp;	/* set ports */
+							sampacket.srcport[1]=(char)(p->sp>>8);
+							sampacket.dstport[0]=(char)p->dp;
+							sampacket.dstport[1]=(char)(p->dp>>8);
+						}
+						else
+							sampacket.srcport[0]=sampacket.srcport[1]=sampacket.dstport[0]=sampacket.dstport[1]=0;
+
+						sampacket.sig_id[0]=(char)event->sig_id;		/* set signature ID */
+						sampacket.sig_id[1]=(char)(event->sig_id>>8);
+						sampacket.sig_id[2]=(char)(event->sig_id>>16);
+						sampacket.sig_id[3]=(char)(event->sig_id>>24);
+
+#ifdef FWSAMDEBUG
+						LogMessage("DEBUG => [Alert_FWsam] Sending BLOCK\n");
+						LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo:  %x\n",station->myseqno);
+						LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo :  %x\n",station->stationseqno);
+						LogMessage("DEBUG => [Alert_FWsam] Status     :  %i\n",FWSAM_STATUS_BLOCK);
+						LogMessage("DEBUG => [Alert_FWsam] Mode       :  %i\n",optp->how|optp->who|optp->loglevel);
+						LogMessage("DEBUG => [Alert_FWsam] Duration   :  %li\n",optp->duration);
+						LogMessage("DEBUG => [Alert_FWsam] Protocol   :  %i\n",GET_IPH_PROTO(p));
+#ifdef SUP_IP6
+						LogMessage("DEBUG => [Alert_FWsam] Src IP     :  %s\n",sfip_ntoa(GET_SRC_IP(p)));
+						LogMessage("DEBUG => [Alert_FWsam] Dest IP    :  %s\n",sfip_ntoa(GET_DST_IP(p)));
+#else
+						LogMessage("DEBUG => [Alert_FWsam] Src IP     :  %s\n",inet_ntoa(p->iph->ip_src));
+						LogMessage("DEBUG => [Alert_FWsam] Dest IP    :  %s\n",inet_ntoa(p->iph->ip_dst));
+#endif
+						LogMessage("DEBUG => [Alert_FWsam] Src Port   :  %i\n",p->sp);
+						LogMessage("DEBUG => [Alert_FWsam] Dest Port  :  %i\n",p->dp);
+						LogMessage("DEBUG => [Alert_FWsam] Sig_ID     :  %lu\n",event->sig_id);
+
+#endif
+
+						encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get the encryption buffer */
+						len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt the packet with current key */
+
+						if(send(stationsocket,encbuf,len,0)!=len) /* weird...could not send */
+						{	LogMessage("WARNING => [Alert_FWsam] Could not send to host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+							closesocket(stationsocket);
+#else
+							close(stationsocket);
+#endif
+							stationtry=0;
+						}
+						else
+						{	i=FWSAM_NETWAIT;
+#ifdef WIN32
+							ioctlsocket(stationsocket,FIONBIO,&i);	/* set non blocking and wait for  */
+#else
+							ioctl(stationsocket,FIONBIO,&i);		/* set non blocking and wait for  */
+#endif
+							while(i-- >1)							/* the response packet	 */
+							{	waitms(10); /* wait for response (default maximum 3 secs */
+								if(recv(stationsocket,encbuf,len,0)==len)
+									i=0; /* if we received packet we set the counter to 0. */
+										 /* by the time we check with if, it's already dec'ed to -1 */
+							}
+							if(!i) /* id we timed out (i was one, then dec'ed)... */
+							{	LogMessage("WARNING => [Alert_FWsam] Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+								closesocket(stationsocket);
+#else
+								close(stationsocket);
+#endif
+								stationtry=0;
+							}
+							else /* got a packet */
+							{	decbuf=(char *)&sampacket; /* get the pointer to the packet struct */
+								len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt the packet with current key */
+
+								if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+								{	strcpy(station->stationkey,station->initialkey); /* try the intial key */
+									TwoFishDestroy(station->stationfish);
+									station->stationfish=TwoFishInit(station->stationkey); /* re-initialize the TwoFish with the intial key */
+									len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try again to decrypt */
+									LogMessage("INFO => [Alert_FWsam] Had to use initial key!\n");
+								}
+								if(len==sizeof(FWsamPacket)) /* valid decryption */
+								{	if(sampacket.version==FWSAM_PACKETVERSION)/* master speaks my language */
+									{	if(sampacket.status==FWSAM_STATUS_OK || sampacket.status==FWSAM_STATUS_NEWKEY
+										|| sampacket.status==FWSAM_STATUS_RESYNC || sampacket.status==FWSAM_STATUS_HOLD)
+										{	station->stationseqno=sampacket.fwseqno[0] | (sampacket.fwseqno[1]<<8); /* get stations seqno */
+											station->lastcontact=(unsigned long)time(NULL); /* set the last contact time (not used yet) */
+#ifdef FWSAMDEBUG
+									LogMessage("DEBUG => [Alert_FWsam] Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK":
+																		   sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY":
+																		   sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC":
+																		   sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR");
+									LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo:  %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8));
+									LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo :  %x\n",station->stationseqno);
+									LogMessage("DEBUG => [Alert_FWsam] Status     :  %i\n",sampacket.status);
+									LogMessage("DEBUG => [Alert_FWsam] Version    :  %i\n",sampacket.version);
+#endif
+											if(sampacket.status==FWSAM_STATUS_HOLD)
+											{	i=FWSAM_NETHOLD;			/* Stay on hold for a maximum of 60 secs (default) */
+												while(i-- >1)							/* the response packet	 */
+												{	waitms(10); /* wait for response  */
+													if(recv(stationsocket,encbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,0)==sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE)
+													  i=0; /* if we received packet we set the counter to 0. */
+										 		}
+												if(!i) /* id we timed out (i was one, then dec'ed)... */
+												{	LogMessage("WARNING => [Alert_FWsam] Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+													stationtry=0;
+													sampacket.status=FWSAM_STATUS_ERROR;
+												}
+												else /* got a packet */
+												{	decbuf=(char *)&sampacket; /* get the pointer to the packet struct */
+													len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt the packet with current key */
+
+													if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+													{	strcpy(station->stationkey,station->initialkey); /* try the intial key */
+														TwoFishDestroy(station->stationfish);
+														station->stationfish=TwoFishInit(station->stationkey); /* re-initialize the TwoFish with the intial key */
+														len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try again to decrypt */
+														LogMessage("INFO => [Alert_FWsam] Had to use initial key again!\n");
+													}
+#ifdef FWSAMDEBUG
+									LogMessage("DEBUG => [Alert_FWsam] Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK":
+																		   sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY":
+																		   sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC":
+																		   sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR");
+									LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo:  %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8));
+									LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo :  %x\n",station->stationseqno);
+									LogMessage("DEBUG => [Alert_FWsam] Status     :  %i\n",sampacket.status);
+									LogMessage("DEBUG => [Alert_FWsam] Version    :  %i\n",sampacket.version);
+#endif
+													if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+													{	ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+														deletestation=TRUE;
+														sampacket.status=FWSAM_STATUS_ERROR;
+													}
+													else if(sampacket.version!=FWSAM_PACKETVERSION) /* invalid protocol version */
+													{	ErrorMessage("ERROR => [Alert_FWsam] Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+														deletestation=TRUE;
+														sampacket.status=FWSAM_STATUS_ERROR;
+													}
+													else if(sampacket.status!=FWSAM_STATUS_OK && sampacket.status!=FWSAM_STATUS_NEWKEY && sampacket.status!=FWSAM_STATUS_RESYNC)
+													{	ErrorMessage("ERROR => [Alert_FWsam] Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+														deletestation=TRUE;
+														sampacket.status=FWSAM_STATUS_ERROR;
+													}
+												}
+											}
+											if(sampacket.status==FWSAM_STATUS_RESYNC)  /* if station want's to resync... */
+											{	strcpy(station->stationkey,station->initialkey); /* ...we use the intial key... */
+												memcpy(station->fwkeymod,sampacket.duration,4);	 /* and note the random key modifier */
+											}
+											if(sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC)
+											{
+												FWsamNewStationKey(station,&sampacket); /* generate new TwoFish keys */
+#ifdef FWSAMDEBUG
+													LogMessage("DEBUG => [Alert_FWsam] Generated new encryption key...\n");
+#endif
+											}
+#ifdef WIN32
+											closesocket(stationsocket);
+#else
+											close(stationsocket);
+#endif
+											stationtry=0;
+										}
+										else if(sampacket.status==FWSAM_STATUS_ERROR) /* if SnortSam reports an error on second try, */
+										{
+#ifdef WIN32
+											closesocket(stationsocket);				  /* something is messed up and ... */
+#else
+											close(stationsocket);
+#endif
+											if(stationtry>1)						  /* we ignore that station. */
+											{	deletestation=TRUE;					  /* flag for deletion */
+												ErrorMessage("ERROR => [Alert_FWsam] Could not renegotiate key! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+											}
+											else							/* if we get an error on the first try, */
+											{	if(!FWsamCheckIn(station))	/* we first try to check in again. */
+												{	deletestation=TRUE;
+													ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+												}
+											}
+										}
+										else /* an unknown status means trouble... */
+										{	ErrorMessage("ERROR => [Alert_FWsam] Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+											closesocket(stationsocket);
+#else
+											close(stationsocket);
+#endif
+											deletestation=TRUE;
+										}
+									}
+									else   /* if the SnortSam agent uses a different packet version, we have no choice but to ignore it. */
+									{	ErrorMessage("ERROR => [Alert_FWsam] Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+										closesocket(stationsocket);
+#else
+										close(stationsocket);
+#endif
+										deletestation=TRUE;
+									}
+								}
+								else /* if the intial key failed to decrypt as well, the keys are not configured the same, and we ignore that SnortSam station. */
+								{	ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+									closesocket(stationsocket);
+#else
+									close(stationsocket);
+#endif
+									deletestation=TRUE;
+								}
+							}
+						}
+						free(encbuf); /* release of the TwoFishAlloc'ed encryption buffer */
+					}
+					if(stationtry==0 || deletestation)		/* if everything went real well, or real bad... */
+					{	if(deletestation){					/* If it went bad, we remove the station from the list by marking the IP */
+//							station->stationip.s_addr=0;
+							station->stationip.ip32[0]=0;
+                                                }
+						fwsamlist=fwsamlist->next;
+					}
+				}
+				else
+					fwsamlist=fwsamlist->next;
+			}
+		}
+		else
+		{
+#ifdef FWSAMDEBUG
+			LogMessage("DEBUG => [Alert_FWsam] Skipping repetitive block.\n");
+#endif
+		}
+	}
+}
+
+/*  FWsamCheckOut will be called when Snort exists. It de-registeres this snort sensor
+ *  from the list of sensor that the SnortSam agent keeps.
+ */
+void FWsamCheckOut(FWsamStation *station)
+{	FWsamPacket sampacket;
+	SOCKET stationsocket;
+	int i,len;
+    char *encbuf,*decbuf;
+	//unsigned char *encbuf,*decbuf;
+
+
+	stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+	if(stationsocket==INVALID_SOCKET)
+		FatalError("ERROR => [Alert_FWsam](FWsamCheckOut) Funky socket error (socket)!\n");
+	if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr)))
+		FatalError("ERROR => [Alert_FWsam](FWsamCheckOut) Could not bind socket!\n");
+
+	/* let's connect to the agent */
+	if(!connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr)))
+	{	LogMessage("INFO => [Alert_FWsam](FWsamCheckOut) Disconnecting from host %s.\n",sfip_ntoa(&station->stationip));
+		/* now build the packet */
+		station->myseqno+=station->stationseqno; /* increase my seqno */
+		sampacket.endiancheck=1;
+		sampacket.snortseqno[0]=(char)station->myseqno;
+		sampacket.snortseqno[1]=(char)(station->myseqno>>8);
+		sampacket.fwseqno[0]=(char)station->stationseqno; /* fill station seqno */
+		sampacket.fwseqno[1]=(char)(station->stationseqno>>8);
+		sampacket.status=FWSAM_STATUS_CHECKOUT;  /* checking out... */
+		sampacket.version=FWSAM_PACKETVERSION;
+
+#ifdef FWSAMDEBUG
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Sending CHECKOUT\n");
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Snort SeqNo:  %x\n",station->myseqno);
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Mgmt SeqNo :  %x\n",station->stationseqno);
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Status     :  %i\n",sampacket.status);
+
+#endif
+
+		encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get encryption buffer */
+		len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt packet with current key */
+
+		if(send(stationsocket,encbuf,len,0)==len)
+		{	i=FWSAM_NETWAIT;
+#ifdef WIN32
+			ioctlsocket(stationsocket,FIONBIO,&i);	/* set non blocking and wait for  */
+#else
+			ioctl(stationsocket,FIONBIO,&i);		/* set non blocking and wait for  */
+#endif
+			while(i-- >1)
+			{	waitms(10);					/* ...wait a maximum of 3 secs for response... */
+				if(recv(stationsocket,encbuf,len,0)==len) /* ... for the status packet */
+					i=0;
+			}
+			if(i) /* if we got the packet */
+			{	decbuf=(char *)&sampacket;
+				len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish);
+
+				if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+				{	strcpy(station->stationkey,station->initialkey); /* try initial key */
+					TwoFishDestroy(station->stationfish);			 /* toss this fish */
+					station->stationfish=TwoFishInit(station->stationkey); /* re-initialze TwoFish with initial key */
+					len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* and try to decrypt again */
+					LogMessage("INFO => [Alert_FWsam](FWsamCheckOut) Had to use initial key!\n");
+				}
+				if(len==sizeof(FWsamPacket)) /* valid decryption */
+				{	if(sampacket.version!=FWSAM_PACKETVERSION) /* but don't really care since we are on the way out */
+						ErrorMessage("WARNING => [Alert_FWsam](FWsamCheckOut) Protocol version error! What the hell, we're quitting anyway! :)\n");
+				}
+				else
+					ErrorMessage("WARNING => [Alert_FWsam](FWsamCheckOut) Password mismatch! What the hell, we're quitting anyway! :)\n");
+			}
+		}
+		free(encbuf); /* release TwoFishAlloc'ed buffer */
+	}
+	else
+		LogMessage("WARNING => [Alert_FWsam] Could not connect to host %s for CheckOut. What the hell, we're quitting anyway! :)\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+	closesocket(stationsocket);
+#else
+	close(stationsocket);
+#endif
+}
+
+
+/*   FWSamFree: Disconnects all FW-1 management stations,
+ *   closes sockets, and frees the structures.
+ */
+void FWsamFree(FWsamList *list)
+{
+    FWsamList *next;
+
+    while(list)	/* Free pointer list for rule type */
+    {
+        next=list->next;
+        free(list);
+        list=next;
+    }
+    list=FWsamStationList;
+
+    while(list) /* Free global pointer list and stations */
+    {
+        next=list->next;
+        if (list->station)
+        {
+            if(list->station->stationip.ip32[0])
+            //if(list->station->stationip.s_addr)
+                FWsamCheckOut(list->station); /* Send a Check-Out to SnortSam, */
+
+            TwoFishDestroy(list->station->stationfish);	/* toss the fish, */
+            free(list->station); /* free station, */
+        }
+        free(list); /* free pointer, */
+        list=next; /* and move to next. */
+    }
+    FWsamStationList=NULL;
+    if(FWsamOptionField)
+        free(FWsamOptionField);
+}
+
+void AlertFWsamCleanExitFunc(int signal, void *arg)
+{	FWsamList *fwsamlist;
+
+#ifdef FWSAMDEBUG
+    LogMessage("DEBUG => [Alert_FWsam](AlertFWsamCleanExitFunc) Exiting...\n");
+#endif
+
+	fwsamlist=(FWsamList *)arg;
+	FWsamFree(fwsamlist); /* Free all elements */
+}
+
+void AlertFWsamRestartFunc(int signal, void *arg)
+{	FWsamList *fwsamlist;
+
+#ifdef FWSAMDEBUG
+    LogMessage("DEBUG => [Alert_FWsam](AlertFWsamRestartFunc) Restarting...\n");
+#endif
+
+	fwsamlist=(FWsamList *)arg;
+	FWsamFree(fwsamlist); /* Free all elements */
+}
+
+/*  This routine registers this Snort sensor with SnortSam.
+ *  It will also change the encryption key based on some variables.
+ */
+int FWsamCheckIn(FWsamStation *station)
+{	int i,len,stationok=TRUE;
+	FWsamPacket sampacket;
+    char *encbuf,*decbuf;
+	//unsigned char *encbuf,*decbuf;
+	SOCKET stationsocket;
+
+
+	/* create a socket for the station */
+	stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+	if(stationsocket==INVALID_SOCKET)
+		FatalError("ERROR => [Alert_FWsam](FWsamCheckIn) Funky socket error (socket)!\n");
+	if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr)))
+		FatalError("ERROR => [Alert_FWsam](FWsamCheckIn) Could not bind socket!\n");
+
+	i=TRUE;
+	/* let's connect to the agent */
+	if(connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr)))
+		LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Could not connect to host %s. Will try later.\n",sfip_ntoa(&station->stationip));
+	else
+	{	LogMessage("INFO => [Alert_FWsam](FWsamCheckIn) Connected to host %s.\n",sfip_ntoa(&station->stationip));
+		/* now build the packet */
+		sampacket.endiancheck=1;
+		sampacket.snortseqno[0]=(char)station->myseqno; /* fill my sequence number number */
+		sampacket.snortseqno[1]=(char)(station->myseqno>>8); /* fill my sequence number number */
+		sampacket.status=FWSAM_STATUS_CHECKIN; /* let's check in */
+		sampacket.version=FWSAM_PACKETVERSION; /* set the packet version */
+		memcpy(sampacket.duration,station->mykeymod,4);  /* we'll send SnortSam our key modifier in the duration slot */
+											   /* (the checkin packet is just the plain initial key) */
+#ifdef FWSAMDEBUG
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Sending CheckIn\n");
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Snort SeqNo:  %x\n",station->myseqno);
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Mode       :  %i\n",sampacket.status);
+			LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Version    :  %i\n",sampacket.version);
+#endif
+		encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get buffer for encryption */
+		len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt with initial key */
+		if(send(stationsocket,encbuf,len,0)!=len) /* weird...could not send */
+			LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Could not send to host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+		else
+		{	i=FWSAM_NETWAIT;
+#ifdef WIN32
+			ioctlsocket(stationsocket,FIONBIO,&i);	/* set non blocking and wait for  */
+#else
+			ioctl(stationsocket,FIONBIO,&i);		/* set non blocking and wait for  */
+#endif
+			while(i-- >1)
+			{	waitms(10); /* wait a maximum of 3 secs for response */
+				if(recv(stationsocket,encbuf,len,0)==len)
+					i=0;
+			}
+			if(!i) /* time up? */
+				LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+			else
+			{	decbuf=(char *)&sampacket; /* got status packet */
+				len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt with initial key */
+				if(len==sizeof(FWsamPacket)) /* valid decryption */
+				{
+#ifdef FWSAMDEBUG
+					LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK":
+															   sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY":
+															   sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC":
+															   sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR");
+					LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Snort SeqNo:  %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8));
+					LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Mgmt SeqNo :  %x\n",sampacket.fwseqno[0]|(sampacket.fwseqno[1]<<8));
+					LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Status     :  %i\n",sampacket.status);
+					LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Version    :  %i\n",sampacket.version);
+#endif
+					if(sampacket.version==FWSAM_PACKETVERSION) /* master speaks my language */
+					{	if(sampacket.status==FWSAM_STATUS_OK || sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC)
+						{	station->stationseqno=sampacket.fwseqno[0]|(sampacket.fwseqno[1]<<8); /* get stations seqno */
+							station->lastcontact=(unsigned long)time(NULL);
+
+							if(sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC)	/* generate new keys */
+							{	memcpy(station->fwkeymod,sampacket.duration,4); /* note the key modifier */
+								FWsamNewStationKey(station,&sampacket); /* and generate new TwoFish keys (with key modifiers) */
+#ifdef FWSAMDEBUG
+				LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Generated new encryption key...\n");
+#endif
+							}
+						}
+						else /* weird, got a strange status back */
+						{	ErrorMessage("ERROR => [Alert_FWsam](FWsamCheckIn) Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+							stationok=FALSE;
+						}
+					}
+					else /* packet version does not match */
+					{	ErrorMessage("ERROR =>[Alert_FWsam](FWsamCheckIn) Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+						stationok=FALSE;
+					}
+				}
+				else /* key does not match */
+				{	ErrorMessage("ERROR => [Alert_FWsam](FWsamCheckIn) Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+					stationok=FALSE;
+				}
+			}
+		}
+		free(encbuf); /* release TwoFishAlloc'ed buffer */
+	}
+#ifdef WIN32
+	closesocket(stationsocket);
+#else
+	close(stationsocket);
+#endif
+	return stationok;
+}
+#undef FWSAMDEBUG
+

Index: snort-2.8.6/src/output-plugins/spo_alert_fwsam.h
===================================================================
--- snort-2.8.6/src/output-plugins/spo_alert_fwsam.h	(Revision 0)
+++ snort-2.8.6/src/output-plugins/spo_alert_fwsam.h	(Revision 3)
@@ -0,0 +1,216 @@
+/* $Id: snortpatchb,v 1.5 2005/10/06 08:50:39 fknobbe Exp $
+**
+** spo_alert_fwsam.h
+**
+** Copyright (c) 2001-2004 Frank Knobbe <frank@knobbe.us>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* This file gets included in plugbase.c when it is integrated into the rest
+ * of the program.
+ *
+ * For more info, see the beginning of spo_alert_fwsam.c
+ *
+ */
+
+#ifndef __SPO_FWSAM_H__
+#define __SPO_FWSAM_H__
+
+#include "snort.h"
+#include "rules.h"
+#include "plugbase.h"
+#include "plugin_enum.h"
+#include "fatal.h"
+#include "util.h"
+#include "twofish.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+
+/* just some compatibility stuff */
+#ifdef WIN32
+#if !defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+#include <winsock.h>
+#endif
+#define	waitms(x)				Sleep(x)
+
+#else
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+
+#ifdef SOLARIS
+#include <sys/filio.h>
+#endif
+
+typedef int SOCKET;
+
+#ifndef INVALID_SOCKET
+#define INVALID_SOCKET	-1
+#endif
+
+#define	waitms(x)				usleep((x)*1000)
+
+#endif
+
+#ifndef	FALSE
+#define FALSE	0
+#endif
+#ifndef	TRUE
+#define	TRUE	!FALSE
+#endif
+#ifndef	bool
+#define	bool	int
+#endif
+
+
+#if defined(_DEBUG) || defined(DEBUG)
+#ifndef FWSAMDEBUG
+#define FWSAMDEBUG
+#endif
+#else
+#endif
+
+
+/* Official Snort PlugIn Number has been moved into plugin_enum.h */
+
+
+/* fixed defines */
+
+#define FWSAM_DEFAULTPORT		898	/* Default port if user does not specify one in snort.conf */
+									/* (Was unused last time I checked...) */
+#define FWSAM_PACKETVERSION		14	/* version of the packet. Will increase with enhancements. */
+
+#define FWSAM_STATUS_CHECKIN	1	/* snort to fw */
+#define FWSAM_STATUS_CHECKOUT	2
+#define FWSAM_STATUS_BLOCK		3
+#define FWSAM_STATUS_UNBLOCK	9
+
+#define FWSAM_STATUS_OK			4	/* fw to snort */
+#define FWSAM_STATUS_ERROR		5
+#define FWSAM_STATUS_NEWKEY		6
+#define FWSAM_STATUS_RESYNC		7
+#define FWSAM_STATUS_HOLD		8
+
+#define FWSAM_LOG_NONE			0
+#define FWSAM_LOG_SHORTLOG		1
+#define FWSAM_LOG_SHORTALERT	2
+#define FWSAM_LOG_LONGLOG		3
+#define FWSAM_LOG_LONGALERT		4
+#define FWSAM_LOG				(FWSAM_LOG_SHORTLOG|FWSAM_LOG_SHORTALERT|FWSAM_LOG_LONGLOG|FWSAM_LOG_LONGALERT)
+#define	FWSAM_WHO_DST			8
+#define FWSAM_WHO_SRC			16
+#define FWSAM_WHO				(FWSAM_WHO_DST|FWSAM_WHO_SRC)
+#define FWSAM_HOW_IN			32
+#define FWSAM_HOW_OUT			64
+#define FWSAM_HOW_INOUT			(FWSAM_HOW_IN|FWSAM_HOW_OUT)
+#define FWSAM_HOW_THIS			128
+#define FWSAM_HOW				(FWSAM_HOW_IN|FWSAM_HOW_OUT|FWSAM_HOW_THIS)
+
+
+/* user adjustable defines */
+
+#define FWSAM_REPET_BLOCKS		10	/* Snort remembers this amount of last blocks and... */
+#define FWSAM_REPET_TIME		20	/* ...checks if they fall within this time. If so,... */
+									/* ...the blocking request is not send. */
+
+#define FWSAM_NETWAIT			300		/* 100th of a second. 3 sec timeout for network connections */
+#define FWSAM_NETHOLD			6000	/* 100th of a second. 60 sec timeout for holding */
+
+#define SID_MAPFILE				"sid-block.map"
+#define SID_ALT_MAPFILE			"sid-fwsam.map"
+
+#define FWSAM_FANCYFETCH        /* This will invoke a fast sid lookup routine */
+
+
+/* vars */
+
+typedef struct _FWsamstation		/* structure of a mgmt station */
+{	unsigned short 		myseqno;
+	unsigned short 		stationseqno;
+	unsigned char		mykeymod[4];
+	unsigned char		fwkeymod[4];
+	unsigned short		stationport;
+	//struct in_addr		stationip;
+	sfip_t			stationip;
+	struct sockaddr_in	localsocketaddr;
+	struct sockaddr_in	stationsocketaddr;
+	TWOFISH			*stationfish;
+	char			initialkey[TwoFish_KEY_LENGTH+2];
+	char			stationkey[TwoFish_KEY_LENGTH+2];
+	time_t			lastcontact;
+/*	time_t			sleepstart; */
+}	FWsamStation;
+
+typedef struct _FWsampacket			/* 2 blocks (3rd block is header from TwoFish) */
+{	unsigned short		endiancheck;	/* 0  */
+	unsigned char		srcip[4];		/* 2  */
+	unsigned char		dstip[4];		/* 6  */
+	unsigned char		duration[4];	/* 10 */
+	unsigned char		snortseqno[2];	/* 14 */
+	unsigned char		fwseqno[2];		/* 16 */
+	unsigned char		srcport[2];		/* 18 */
+	unsigned char		dstport[2];		/* 20 */
+	unsigned char		protocol[2];	/* 22 */
+	unsigned char		fwmode;			/* 24 */
+	unsigned char		version;		/* 25 */
+	unsigned char		status;			/* 26 */
+	unsigned char		sig_id[4];		/* 27 */
+	unsigned char		fluff;			/* 31 */
+}	FWsamPacket;						/* 32 bytes in size */
+
+typedef struct _FWsamoptions	/* snort rule options */
+{	unsigned long	sid;
+    unsigned long	duration;
+	unsigned char	who;
+	unsigned char	how;
+	unsigned char	loglevel;
+}	FWsamOptions;
+
+typedef struct _FWsamlistpointer
+{	FWsamStation *station;
+	struct _FWsamlistpointer *next;
+}	FWsamList;
+
+
+/* functions */
+void AlertFWsamSetup(void);
+void AlertFWsamInit(char *args);
+void AlertFWsamOptionInit(char *args,OptTreeNode *otn,int protocol);
+void AlertFWsamCleanExitFunc(int signal, void *arg);
+void AlertFWsamRestartFunc(int signal, void *arg);
+void AlertFWsam(Packet *p, char *msg, void *arg, Event *event);
+int FWsamCheckIn(FWsamStation *station);
+void FWsamCheckOut(FWsamStation *station);
+void FWsamNewStationKey(FWsamStation *station,FWsamPacket *packet);
+void FWsamFixPacketEndian(FWsamPacket *p);
+unsigned long FWsamParseDuration(char *p);
+void FWsamFree(FWsamList *fwsamlist);
+int FWsamStationExists(FWsamStation *who,FWsamList *list);
+int FWsamReadLine(char *,unsigned long,FILE *);
+void FWsamParseLine(FWsamOptions *,char *);
+FWsamOptions *FWsamGetOption(unsigned long);
+int FWsamParseOption(FWsamOptions *,char *);
+
+#endif  /* __SPO_FWSAM_H__ */

Index: snort-2.8.6/src/output-plugins/Makefile.am
===================================================================
--- snort-2.8.6/src/output-plugins/Makefile.am	(Revision 1)
+++ snort-2.8.6/src/output-plugins/Makefile.am	(Revision 3)
@@ -11,6 +11,7 @@
 spo_log_tcpdump.h spo_unified.c spo_unified2.c spo_unified.h spo_unified2.h \
 spo_log_ascii.c spo_log_ascii.h spo_alert_sf_socket.h spo_alert_sf_socket.c \
 spo_alert_prelude.c spo_alert_prelude.h spo_alert_arubaaction.c spo_alert_arubaaction.h \
+spo_alert_fwsam.c spo_alert_fwsam.h \
 spo_alert_test.c spo_alert_test.h
 
 INCLUDES = @INCLUDES@
Index: snort-2.8.6/src/plugbase.c
===================================================================
--- snort-2.8.6/src/plugbase.c	(Revision 1)
+++ snort-2.8.6/src/plugbase.c	(Revision 3)
@@ -125,6 +125,7 @@
 #endif
 
 #include "output-plugins/spo_alert_test.h"
+#include "output-plugins/spo_alert_fwsam.h"
 
 extern ListHead *head_tmp;
 extern PreprocConfigFuncNode *preproc_config_funcs;
@@ -1240,6 +1241,7 @@
 #endif
 
     AlertTestSetup();
+    AlertFWsamSetup();
 }
 
 /****************************************************************************
Index: snort-2.8.6/src/Makefile.am
===================================================================
--- snort-2.8.6/src/Makefile.am	(Revision 1)
+++ snort-2.8.6/src/Makefile.am	(Revision 3)
@@ -52,7 +52,8 @@
 detection_filter.c detection_filter.h \
 rate_filter.c rate_filter.h \
 obfuscation.c obfuscation.h \
-rule_option_types.h
+rule_option_types.h \
+twofish.c twofish.h
 
 snort_LDADD = output-plugins/libspo.a \
 detection-plugins/libspd.a            \
Index: snort-2.8.6/autojunk.sh
===================================================================
--- snort-2.8.6/autojunk.sh	(Revision 0)
+++ snort-2.8.6/autojunk.sh	(Revision 3)
@@ -0,0 +1,7 @@
+#!/bin/sh
+# the list of commands that need to run before we do a compile
+libtoolize --automake --copy
+aclocal -I m4
+autoheader
+automake --add-missing --copy
+autoconf

Index: snort-2.8.6/etc/snort.conf
===================================================================
--- snort-2.8.6/etc/snort.conf	(Revision 1)
+++ snort-2.8.6/etc/snort.conf	(Revision 3)
@@ -277,6 +277,32 @@
 # prelude
 # output alert_prelude
 
+# snortsam
+# In order to cause Snort to send a blocking request to the SnortSam agent,
+# that agent has to be listed, including the port it listens on,
+# and the encryption key it is using. The statement for that is:
+#
+# output alert_fwsam: {SnortSam Station}:{port}/{password}
+#
+#  {SnortSam Station}: IP address or host name of the host where SnortSam is running.
+#  {port}:             The port the remote SnortSam agent listens on.
+#  {password}:         The password, or key, used for encryption of the
+#                      communication to the remote agent.
+#
+# At the very least, the IP address or host name of the host running SnortSam
+# needs to be specified. If the port is omitted, it defaults to TCP port 898.
+# If the password is omitted, it defaults to a preset password.
+# (In which case it needs to be omitted on the SnortSam agent as well)
+#
+# More than one host can be specified, but has to be done on the same line.
+# Just separate them with one or more spaces.
+#
+# Examples:
+#
+# output alert_fwsam: firewall/idspassword
+# output alert_fwsam: fw1.domain.tld:898/mykey
+# output alert_fwsam: 192.168.0.1/borderfw  192.168.1.254/wanfw
+
 # metadata reference data.  do not modify these lines
 include classification.config
 include reference.config