diff include/dcc_ck.h @ 0:c7f6b056b673

First import of vendor version
author Peter Gervai <grin@grin.hu>
date Tue, 10 Mar 2009 13:49:58 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/dcc_ck.h	Tue Mar 10 13:49:58 2009 +0100
@@ -0,0 +1,779 @@
+/* Distributed Checksum Clearinghouse
+ *
+ * checksum routines
+ *
+ * Copyright (c) 2008 by Rhyolite Software, LLC
+ *
+ * This agreement is not applicable to any entity which sells anti-spam
+ * solutions to others or provides an anti-spam solution as part of a
+ * security solution sold to other entities, or to a private network
+ * which employs the DCC or uses data provided by operation of the DCC
+ * but does not provide corresponding data to other users.
+ *
+ * Permission to use, copy, modify, and distribute this software without
+ * changes for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear in all
+ * copies and any distributed versions or copies are either unchanged
+ * or not called anything similar to "DCC" or "Distributed Checksum
+ * Clearinghouse".
+ *
+ * Parties not eligible to receive a license under this agreement can
+ * obtain a commercial license to use DCC by contacting Rhyolite Software
+ * at sales@rhyolite.com.
+ *
+ * A commercial license would be for Distributed Checksum and Reputation
+ * Clearinghouse software.  That software includes additional features.  This
+ * free license for Distributed ChecksumClearinghouse Software does not in any
+ * way grant permision to use Distributed Checksum and Reputation Clearinghouse
+ * software
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
+ * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Rhyolite Software DCC 1.3.103-1.182 $Revision$
+ */
+
+#ifndef DCC_CK_H
+#define DCC_CK_H
+
+#include "dcc_clnt.h"
+#include "dcc_md5.h"
+
+
+typedef DCC_TGTS DCC_CKSUM_THOLDS[DCC_DIM_CKS];
+#define DCC_THOLD_NEVER	    (DCC_TGTS_TOO_MANY+1)
+#define DCC_THOLD_UNSET	    (DCC_TGTS_INVALID)
+
+extern DCC_CKSUM_THOLDS dcc_tholds_rej;
+
+
+/* MIME boundary
+ * RFC 1341 says boundaries can be 70 bytes, but handle non-conformant spam */
+#define DCC_CK_BND_MAX	    94
+#define DCC_CK_BND_DIM	(DCC_CK_BND_MAX+2)  /* including leading -- */
+#define DCC_CK_BND_MISS	(DCC_CK_BND_DIM+1)
+typedef struct {
+    u_char	bnd_len;		/* length including leading "--" */
+    u_char	cmp_len;		/* compared so far */
+    char	bnd[DCC_CK_BND_DIM];	/* "--"boundary */
+} DCC_CK_BND;
+
+
+typedef u_char DCC_CK_FC[256];
+extern const DCC_CK_FC dcc_cset_1, dcc_cset_2;
+
+/* state machine for ignoring parts of URLs */
+typedef struct {
+    enum {
+	DCC_URL_ST_IDLE,		/* waiting for H or = */
+	DCC_URL_ST_QUOTE,		/*    "     " '"' or 'H' after = */
+	DCC_URL_ST_QH,			/*    "     "  H after quote */
+	DCC_URL_ST_T1,			/*    "     "  T */
+	DCC_URL_ST_T2,			/*    "     "  T */
+	DCC_URL_ST_P,			/*    "     "  P */
+	DCC_URL_ST_S,			/*    "     "  [S] */
+	DCC_URL_ST_COLON,		/*    "     "  : */
+	DCC_URL_ST_SLASH1,		/*    "     "  / */
+	DCC_URL_ST_SLASH2,		/*    "     "  / */
+	DCC_URL_ST_SLASH3_START,
+	DCC_URL_ST_SLASH3,		/*    "     "  third / */
+	DCC_URL_ST_SKIP			/* skipping rest of URL */
+    } st;
+    char	*start;			/* start of hostname in URL */
+    char	*dot;			/* last '.' in hostname */
+    int		total;			/* length of URL */
+    u_char	flags;
+#    define	 DCC_URL_QUOTED	    0x01
+#    define	 DCC_URL_DEL_DOMAIN 0x02    /* waiting for domain to delete */
+#    define	 DCC_URL_PERCENT1   0x04    /* waiting for 1st digit after % */
+#    define	 DCC_URL_PERCENT2   0x08    /* waiting for 2nd digit after % */
+#    define	 DCC_URL_SQUOTED    0x10    /* single quoted (') URL */
+#    define	 DCC_URL_DQUOTED    0x20    /* double quoted (") URL */
+#    define	 DCC_URL_QUOTES (DCC_URL_DQUOTED | DCC_URL_SQUOTED)
+#    define	 DCC_URL_SIMPLE (DCC_URL_DEL_DOMAIN	\
+				 | DCC_URL_PERCENT1	\
+				 | DCC_URL_PERCENT2)
+    u_char	percent;
+} DCC_URL_SKIP;
+#define DCC_URL_MAX	    65		/* 63 is RFC 1034 limit on labels */
+#define DCC_URL_FAILSAFE    2000	/* big bogus "username:password@" */
+
+
+/* a template for generating a reply to an SMTP command */
+typedef enum {
+    REPLY_TPLT_NULL,
+    REPLY_TPLT_ID,	/* queue ID for sendmail, fake for dccifd */
+    REPLY_TPLT_CIP,	/* SMTP client IP address */
+    REPLY_TPLT_BTYPE,	/* type of DNSBL hit */
+    REPLY_TPLT_BTGT,	/* DNSBL hit IP address or name */
+    REPLY_TPLT_BPROBE,	/* DNSBL probe domain name */
+    REPLY_TPLT_BRESULT	/* DNSBL probe result */
+} REPLY_TPLT_ARGS;
+typedef struct {
+    const char *log_result;		/* "reject" etc. for log */
+#    define NUM_REPLY_TPLT_ARGS 6
+    REPLY_TPLT_ARGS args[NUM_REPLY_TPLT_ARGS];
+    char    rcode[sizeof("5yz")];
+    char    xcode[sizeof("1.2.3")];
+    u_char  is_pat;			/* template has %s references */
+#    define  REPLY_BUF_LEN 256
+    char    pat[REPLY_BUF_LEN];		/* pattern for SMTP message */
+}  REPLY_TPLT;
+
+
+/* specify a DNS blacklist */
+typedef struct {
+    char    c[DCC_MAXDOMAINLEN];	/* null terminated */
+} DNSBL_DOM;
+
+typedef u_char DNSBL_FGS;
+#define	DNSBL_FG_DUP	    0x01	/* duplicate blacklist */
+#define DNSBL_FG_TIMEO	    0x02	/* suffered a timeout */
+#define	DNSBL_FG_TFAIL	    0x04	/* want SMTP failure on timeout */
+#define	DNSBL_FG_CLIENT	    0x08	/* check client IP address */
+#define	DNSBL_FG_MAIL_HOST  0x10	/* check env_from domain */
+#define	DNSBL_FG_URL	    0x20	/* check URLs in message body */
+#define	DNSBL_FG_MX	    0x40	/* MX for _URL & _MAIL_HOST */
+#define	DNSBL_FG_NS	    0x80	/* NS for _URL & _MAIL_HOST */
+# define DNSBL_FG_HITS	   (DNSBL_FG_CLIENT | DNSBL_FG_MAIL_HOST | DNSBL_FG_URL)
+# define DNSBL_FG_TYPES	   (DNSBL_FG_HITS | DNSBL_FG_MX | DNSBL_FG_NS)
+# define DNSBL_FG_DEFAULT   DNSBL_FG_TYPES
+
+typedef enum DNSBL_TYPE {
+    DNSBL_TYPE_IPV4,
+    DNSBL_TYPE_IPV6,
+    DNSBL_TYPE_NAME
+} DNSBL_TYPE;
+
+#define	MAX_DNSBL_GROUPS    3
+typedef u_char	DNSBL_GBITS;
+#define DNSBL_G2B(n) ((1<<(n)) & ((2<<MAX_DNSBL_GROUPS)-1))
+
+typedef struct dnsbl {
+    struct dnsbl *fwd;
+    struct dnsbl *dup;			/* same except result */
+    u_char	group;			/* 1-indexed */
+    struct in6_addr tgt;		/* hit if DNSBL matches this block */
+    struct in6_addr tgt_mask;
+    u_char	tgt_use_ipv6;		/* ipv4 vs. ipv6 result weighting */
+    DNSBL_TYPE	bl_type;
+    int		bl_num;
+    int		bl_dom_len;
+    DNSBL_DOM	bl_dom;
+    const REPLY_TPLT *reply;
+    DNSBL_FGS	fgs;
+} DNSBL;
+
+/* working storage for one set of DNSBLs */
+typedef struct {
+    DNSBL_FGS	fgs;			/* kind of DNSBL hit */
+    const char	*btype;			/* type of hit string */
+    const DNSBL	*dnsbl;			/* hit DNSBL */
+    char	btype_buf[64];
+    char	result[DCC_SU2STR_SIZE];    /* IP address found in DNSBL */
+    DNSBL_DOM	tgt;			/* IP address or name sought in DNSBL */
+    DNSBL_DOM	probe;			/* what was actually looked up */
+} DNSBL_GROUP;
+
+/* working storage for all DNSBLs */
+typedef struct {
+    DNSBL_DOM	dom;			/* domain name */
+    struct in6_addr addr;		/* and/or IP address sought in DNSBL */
+} DNSBL_TGT;
+typedef struct {
+    DNSBL_GBITS all;
+    DNSBL_GBITS	client;
+    DNSBL_GBITS	mail_host;
+    DNSBL_GBITS	mail_host_ns;
+    DNSBL_GBITS	mail_host_mx;
+    DNSBL_GBITS	url;
+    DNSBL_GBITS	url_ns;
+    DNSBL_GBITS	url_mx;
+} DNSBL_UNHIT;
+typedef struct {
+    DCC_CLNT_CTXT *dcc_ctxt;
+    void	*log_ctxt;
+    const char	*id;
+    time_t	msg_us;			/* microseconds remaining for msg */
+    struct timeval url_start;
+    time_t	url_us;			/* microseconds to look up URL */
+    time_t	url_us_used;
+    DNSBL_UNHIT	unhit;			/* groups of DNSBLs not yet hit */
+    u_short	tgt_dom_len;
+    DNSBL_TGT	tgt;
+    struct {
+	DNSBL_DOM   dom;
+    } tgt_cache[8];
+    int		tgt_cache_pos;
+    DNSBL_GROUP	groups[MAX_DNSBL_GROUPS];
+} DNSBL_WORK;
+
+extern DNSBL *dnsbls;
+extern u_char have_dnsbl_groups;
+extern u_char have_helpers;
+extern DCC_PATH dnsbl_progpath;
+
+
+
+/* accumulated checksums for an SMTP message */
+typedef struct {
+    const char *hdr_nm;			/* name if substitute checksum */
+    DCC_TGTS	tgts;			/* server's answer or previous total */
+    DCC_CK_TYPE_B type;
+    u_char	rpt2srvr;		/* 1=report to server */
+    DCC_SUM	sum;
+} DCC_GOT_SUM;
+#define CLR_GOT_SUM(g) ((g)->hdr_nm = 0, (g)->tgts = DCC_TGTS_INVALID,	\
+			(g)->type = DCC_CK_INVALID, (g)->rpt2srvr = 0)
+
+typedef union {
+    u_int32_t	w32[4];
+    u_char	b[16];
+} DCC_FUZ2_WORD;
+#define DCC_FUZ2_WORD_CLEAR(_w) ((_w)->w32[0]=0, (_w)->w32[1]=0,	\
+				 (_w)->w32[2]=0, (_w)->w32[3]=0)
+
+typedef struct {
+    DCC_URL_SKIP url;
+    u_int	total;			/* bytes */
+    char	*cp;			/* end of data in buffer */
+    char	*eol;			/* most recent eol */
+#    define	 DCC_FUZ1_MAX_LINE  78
+#    define	 DCC_HTTPS_STR	    "https"
+#    define	 DCC_HTTPS_LEN	    LITZ(DCC_HTTPS_STR)
+    char	buf[DCC_FUZ1_MAX_LINE*4
+		    +DCC_HTTPS_LEN];
+    MD5_CTX	md5;
+} DCC_CTX_FUZ1;
+
+
+typedef struct {			/* per-language counts */
+    u_int	wsummed;		/* bytes of words summed */
+    u_int	wtotal;			/* words summed */
+    MD5_CTX	md5;
+} FUZ2_LANG;
+
+typedef struct {
+    u_int	btotal;			/* total non-whitespace bytes seen */
+    u_int	xsummed;		/* non-word bytes checksummed */
+    u_int	wlen;			/* length of current word */
+    u_int	cref_cnt;		/* fancy character length */
+    u_int	tag_len;		/* HTML tag length */
+    DCC_FUZ2_WORD w;
+    DCC_FUZ2_WORD cref_w;
+    DCC_FUZ2_WORD tag;
+    int		urls;			/* # of URLs seen */
+    char	*url_cp;		/* accumulated URLs */
+#    define	 DCC_FUZ2_URL_MAX   (1+DCC_URL_MAX)
+    char	url_buf[DCC_FUZ2_URL_MAX*2];
+    DCC_URL_SKIP url;			/* state machine for skipping URLs */
+    enum {
+	DCC_CREF_ST_IDLE = 0,
+	DCC_CREF_ST_START,		/* get HTML character reference */
+	DCC_CREF_ST_NUM,		/*	hex or decimal */
+	DCC_CREF_ST_DEC,
+	DCC_CREF_ST_HEX,
+	DCC_CREF_ST_NAME
+    } cref_st;
+    enum {
+	DCC_FUZ2_ST_WORD = 0,		/* gathering word */
+	DCC_FUZ2_ST_START_TAG,		/* gathering start of HTML tag */
+	DCC_FUZ2_ST_SKIP_TAG,		/* skipping HTML tag */
+	DCC_FUZ2_ST_SKIP_COMMENT	/* skipping HTML comment */
+    } st;
+#    define FUZ2_LAN_NUM 3
+    FUZ2_LANG	lang[FUZ2_LAN_NUM];
+} DCC_CTX_FUZ2;
+
+/* The maximum length of a checksumed HELO value and the continuation string
+ * need to be the same for all users of the local white-/blacklist */
+#define DCC_HELO_MAX	(DCC_MAXDOMAINLEN+8)
+#define	DCC_HELO_CONT	"..."
+
+/* local-part maximum in RFC 2821 */
+#define DCC_LOCAL_PART_MAX  64
+#define DCC_ENV_FROM_MAX    (DCC_LOCAL_PART_MAX+DCC_MAXDOMAINLEN)
+
+#define DCC_MSG_ID_LEN	    24
+
+/* do not checksum more than this much of a header line */
+#define DCC_HDR_CK_MAX	1024
+
+/* substitute or locally configured checksums */
+#define DCC_MAX_SUB_CKS 6
+
+#define DCC_WSUMS (DCC_DIM_CKS+DCC_MAX_SUB_CKS)	/* max whitelist checksums */
+typedef struct {
+    DCC_GOT_SUM	sums[DCC_WSUMS];
+    struct in6_addr ip_addr;		/* SMTP client IP address */
+    struct {				/*  quoted-printable state machine */
+	int	    x;
+	int	    y;
+	u_char	    n;
+	enum {
+	    DCC_CK_QP_IDLE,		/* waiting for '=' */
+	    DCC_CK_QP_EQ,		/* seen "=" */
+	    DCC_CK_QP_1,		/* seen "=X" of "=XY" */
+	    DCC_CK_QP_FAIL1,		/* have output '=' after bad =X */
+	    DCC_CK_QP_FAIL2,		/* have output '=' after bad =XY */
+	    DCC_CK_QP_FAIL3		/* have output 'X' after bad =XY */
+	} state;
+    } qp;
+    struct {				/* base64 state machine */
+	u_int32_t   quantum;
+	int	    quantum_cnt;
+    } b64;
+    enum {
+	CK_MP_ST_PREAMBLE,		/* preamble before first boundary */
+	CK_MP_ST_BND,			/* MIME boundary */
+	CK_MP_ST_HDRS,			/* headers after a boundary */
+	CK_MP_ST_TEXT,			/* body or entity */
+	CK_MP_ST_EPILOGUE		/* text after last boundary */
+    } mp_st;
+    enum CK_MHDR_ST {			/* parse entity fields */
+	CK_MHDR_ST_IDLE,
+	CK_MHDR_ST_CE_CT,		/* matching "Content-T" */
+	CK_MHDR_ST_CE,			/*	"ransfer-Encoding:" */
+	CK_MHDR_ST_CE_WS,		/* white space after "encoding:" */
+	CK_MHDR_ST_CT,			/*	"ype:" */
+	CK_MHDR_ST_CT_WS,		/* white space after "type:" */
+	CK_MHDR_ST_QP,			/*	"quoted-printable" */
+	CK_MHDR_ST_B64,			/*	"base64" */
+	CK_MHDR_ST_TEXT,		/*	"text" */
+	CK_MHDR_ST_HTML,		/*	"/html" */
+	CK_MHDR_ST_CSET_SKIP_PARAM,	/*	skip to ";" after "text" */
+	CK_MHDR_ST_CSET_SPAN_WS,	/*	skip blanks before "charset" */
+	CK_MHDR_ST_CSET,		/* match "charset=" */
+	CK_MHDR_ST_CSET_ISO_8859,	/*	"ISO-8859-" */
+	CK_MHDR_ST_CSET_ISO_X,		/* find the 8859 type number */
+	CK_MHDR_ST_MULTIPART,		/* match "multipart" */
+	CK_MHDR_ST_BND_SKIP_PARAM,	/* skip "/alternative;" or similar */
+	CK_MHDR_ST_BND_SPAN_WS,		/* skip whitespace before "boundary" */
+	CK_MHDR_ST_BND,			/* match "boundary=" */
+	CK_MHDR_ST_BND_VALUE		/* collecting boundary */
+    } mhdr_st;
+    u_char	mhdr_pos;
+    u_char	mime_nest;		/* # of nested MIME entities */
+    u_char	mime_bnd_matches;	/* # of active boundary matches */
+    DCC_CK_BND	mime_bnd[3];
+    enum {
+	DCC_CK_CT_TEXT = 0,
+	DCC_CK_CT_HTML,
+	DCC_CK_CT_BINARY
+    } mime_ct;
+    const u_char *mime_cset;
+    enum {
+	DCC_CK_CE_ASCII = 0,
+	DCC_CK_CE_QP,
+	DCC_CK_CE_B64
+    } mime_ce;
+    struct {
+	u_int	    total;		/* non-whitespace text */
+	u_char	    flen;		/* bytes of ">From" seen */
+	MD5_CTX	    md5;
+    } ctx_body;
+    DCC_CTX_FUZ1 fuz1;
+    DCC_CTX_FUZ2 fuz2;
+    DNSBL_WORK	*dnsbl;			/* pointer to malloc()'ed state */
+    DCC_CKSUM_THOLDS tholds_rej;
+    u_char	flags;
+#    define	 DCC_CKS_MIME_BOL	0x01    /* header decoder is at BOL */
+#    define	 DCC_CKS_MIME_QUOTED	0x02    /* quoted boundary */
+} DCC_GOT_CKS;
+
+typedef DCC_TGTS DCC_CKS_WTGTS[DCC_WSUMS];
+
+
+/* sscanf() a checksum */
+#define DCC_CKSUM_HEX_PAT	"%8x %8x %8x %8x"
+
+
+
+
+/* whiteclnt files */
+
+#define DCC_WHITE_SUFFIX	".dccw"
+#define DCC_WHITE_NEW_SUFFIX	".dccx"	/* hash table under construction */
+
+typedef char DCC_WHITE_MAGIC[128];
+#define WHITE_MAGIC_B_STR "DCC client whitelist hash table version "
+#define WHITE_MAGIC_V_STR "23"
+
+typedef struct {
+    DCC_TGTS	tgts;
+    int		bits;
+    struct in6_addr addr;
+    struct in6_addr mask;
+    u_short	lno;
+    u_char	fno;
+} DCC_WHITE_CIDR_ENTRY;
+
+typedef struct {
+    u_char	len;
+#    define	 WHITE_CIDR_MAX_ENTRIES 64
+    DCC_WHITE_CIDR_ENTRY e[WHITE_CIDR_MAX_ENTRIES];
+} DCC_WHITE_CIDR;
+
+typedef u_int DCC_WHITE_INX;		/* 1-based index into hash table */
+
+typedef struct {
+    DCC_WHITE_INX fwd;
+    DCC_TGTS	tgts;
+    u_short	lno;
+    u_char	fno;
+    DCC_CK_TYPE_B type;
+    DCC_SUM	sum;
+} DCC_WHITE_ENTRY;
+
+#ifdef DCC_WIN32
+#define DCC_WHITE_TBL_BINS 521		/* should be prime */
+#else
+#define DCC_WHITE_TBL_BINS 8209		/* should be prime */
+#endif
+typedef u_int DCC_WHITE_FGS;
+typedef struct {
+    DCC_WHITE_MAGIC magic;		/* WHITE_MAGIC_* in ckwhite.c */
+    struct {
+	DCC_WHITE_INX entries;		/* # of entries in the file */
+	DCC_WHITE_FGS flags;
+#	 define	 DCC_WHITE_FG_PER_USER	    0x00000001
+#	 define	 DCC_WHITE_FG_HOSTNAMES	    0x00000002	/* have some */
+#	 define	 DCC_WHITE_FG_GREY_LOG_ON   0x00000004
+#	 define	 DCC_WHITE_FG_GREY_LOG_OFF  0x00000008
+#	 define	 DCC_WHITE_FG_GREY_ON	    0x00000010
+#	 define	 DCC_WHITE_FG_GREY_OFF	    0x00000020
+#	 define	 DCC_WHITE_FG_LOG_ALL	    0x00000040
+#	 define	 DCC_WHITE_FG_LOG_NORMAL    0x00000080
+#	 define	 DCC_WHITE_FG_DISCARD_OK    0x00000100
+#	 define	 DCC_WHITE_FG_NO_DISCARD    0x00000200
+#	 define	 DCC_WHITE_FG_DCC_ON	    0x00000400
+#	 define	 DCC_WHITE_FG_DCC_OFF	    0x00000800
+#	 define	 DCC_WHITE_FG_REP_ON	    0x00001000
+#	 define	 DCC_WHITE_FG_REP_OFF	    0x00002000
+#	 define	 DCC_WHITE_FG_MTA_FIRST	    0x00004000
+#	 define	 DCC_WHITE_FG_MTA_LAST	    0x00008000
+#	 define	 DCC_WHITE_FG_LOG_D	    0x00010000
+#	 define	 DCC_WHITE_FG_LOG_H	    0x00020000
+#	 define	 DCC_WHITE_FG_LOG_M	    0x00040000
+#	 define	 DCC_WHITE_FG_TRAP_ACC	    0x00080000	/* spam trap */
+#	 define	 DCC_WHITE_FG_TRAP_REJ	    0x00100000	/* spam trap */
+#	  define  DCC_WHITE_FG_TRAPS (DCC_WHITE_FG_TRAP_ACC		\
+				       | DCC_WHITE_FG_TRAP_REJ)
+#	 define	 DCC_WHITE_FG_DNSBL_ON(n)  (0x00200000*DNSBL_G2B(n))
+#	  define  DCC_WHITE_FG_DNSBL_ON_M   0x00e00000
+#	 define	 DCC_WHITE_FG_DNSBL_OFF(n) (0x01000000*DNSBL_G2B(n))
+#	  define  DCC_WHITE_FG_DNSBL_OFF_M  0x07000000
+	time_t	reparse;		/* re-parse after this */
+	time_t	broken;			/* serious broken until then */
+	time_t	ascii_mtime;		/* ASCII file mtime at last parsing */
+	struct {			/* included files */
+	    time_t	mtime;
+	    DCC_PATH	nm;
+	} white_incs[8];
+
+	DCC_CKSUM_THOLDS tholds_rej;
+
+	DCC_SUM	ck_sum;			/* checksum of following contents */
+	DCC_WHITE_CIDR cidr;
+    } hdr;
+    DCC_WHITE_INX bins[DCC_WHITE_TBL_BINS]; /* 1-based indeces or 0 for empty */
+    DCC_WHITE_ENTRY tbl[1];
+} DCC_WHITE_TBL;
+
+
+/* a ASCII whiteclnt file (including the files it includes) can be
+ *	OK
+ *	unreadable or otherwise badly broken
+ *	missing
+ *	    if permanent, the hash table should be removed, but
+ *	    it might be temporary as an editor changes it
+ * a hash table can be
+ *	OK
+ *	out of date compared to the ASCII file(s)
+ *	badly broken but not removable (e.g. bad directory permissions).
+ *
+ * Do not stat() the files iand so do not complain on every message by
+ *	using wf->next_stat_time
+ * Avoid generating a complaint on every error message using wf->broken
+ * Reparse ASCII files with errors using wf->reparse or when their mtimes
+ *	change, but not more often than we use stat() to check mtimes..
+ * Reparse the main ASCII file if it contains host names by noticing the
+ *	DCC_WHITE_FG_HOSTNAMES bit and that the mtime of the hash table is
+ *	more than DCC_WHITECLNT_RESOLVE seconds old
+ */
+#define DCC_WHITE_REPARSE_DELAY	(30*60)	/* look for new DNS values */
+#define DCC_WHITE_BROKEN_DELAY	(5*60)	/* do not complain more often */
+#define DCC_WHITE_STAT_DELAY	10	/* don't stat() more often */
+
+/* computed from DCC_WHITE_FGS */
+typedef u_int32_t FLTR_SWS;
+#define	FLTR_SW_SET		0x00000001
+#define FLTR_SW_NO_DISCARD	0x00000002  /* always reject spam */
+#define	FLTR_SW_DCC_OFF		0x00000004  /* no DCC check */
+#define	FLTR_SW_REP_ON		0x00000008  /* honor DCC reputation */
+#define	FLTR_SW_LOG_ALL		0x00000010
+#define	FLTR_SW_GREY_OFF	0x00000020  /* greylisting off */
+#define	FLTR_SW_GREY_LOG_OFF	0x00000040  /* log greylist embargos */
+#define FLTR_SW_LOG_D		0x00000080
+#define FLTR_SW_LOG_H		0x00000100
+#define FLTR_SW_LOG_M		0x00000200
+#define	FLTR_SW_MTA_FIRST	0x00000400  /* MTA IS/NOTSPAM checked first */
+#define	FLTR_SW_TRAP_ACC	0x00000800  /* accepting spam trap */
+#define	FLTR_SW_TRAP_REJ	0x00001000  /* rejecting spam trap */
+# define  FLTR_SW_TRAPS (FLTR_SW_TRAP_ACC | FLTR_SW_TRAP_REJ)
+#define	FLTR_SW_DNSBL(n)       (0x00002000*DNSBL_G2B(n))    /* check DNSBL */
+# define FLTR_SW_DNSBL_M	0x0000e000
+# define FLTR_SW_DNSBL_BITS(sws) (((sws)&FLTR_SW_DNSBL_M)		\
+				  / FLTR_SW_DNSBL(0))
+
+/* bits set to enable something */
+#define FLTR_SWS_SETTINGS_ON	(FLTR_SW_REP_ON				\
+				 | FLTR_SW_LOG_ALL			\
+				 | FLTR_SW_MTA_FIRST			\
+				 | FLTR_SW_DNSBL_M			\
+				 | FLTR_SW_TRAPS)
+/* bits set to disable something */
+#define FLTR_SWS_SETTINGS_OFF	(FLTR_SW_DCC_OFF			\
+				 | FLTR_SW_NO_DISCARD			\
+				 | FLTR_SW_TRAP_REJ			\
+				 | FLTR_SW_GREY_OFF			\
+				 | FLTR_SW_GREY_LOG_OFF)
+/* get bits of enabled FILTERS */
+#define FLTR_SWS_ON(sws)    (((sws) ^ FLTR_SW_DCC_OFF)			\
+			     & (FLTR_SW_DCC_OFF				\
+				| FLTR_SW_REP_ON			\
+				| FLTR_SW_DNSBL_M			\
+				| FLTR_SW_TRAP_REJ))
+
+
+/* everything there is to know about a currently active whitelist file */
+typedef struct {
+    DCC_WHITE_TBL *wtbl;
+    int		ht_fd;			/* hash table file */
+    struct stat ht_sb;
+    DCC_WHITE_FGS wtbl_flags;
+    u_int	wtbl_entries;		/* # of entries mapped window */
+    u_int	wtbl_size;		/* bytes in mapped window */
+    time_t	next_stat_time;
+    time_t	reparse;		/* when to re-parse file */
+    time_t	broken;			/* something very sick until then */
+#ifdef DCC_WIN32
+    HANDLE	ht_map;			/* WIN32 hash table map handle */
+#endif
+    u_int	ascii_nm_len;
+    DCC_PATH	ascii_nm;
+    DCC_PATH	ht_nm;
+    int		fno, lno;		/* currently being parsed */
+    u_char	wf_flags;
+#    define	 DCC_WF_PER_USER    0x01    /* hostnames not allowed */
+#    define	 DCC_WF_NOFILE	    0x02    /* no whiteclnt file */
+#    define	 DCC_WF_EITHER	    0x04    /* either global or per-user ok */
+#    define	 DCC_WF_RO	    0x08    /* read only access */
+#    define	 DCC_WF_WLIST	    0x10    /* wlist command */
+#    define	 DCC_WF_WLIST_RO    0x20    /* read-only wlist command */
+#    define	 DCC_WF_WLIST_RW    0x40    /* read/write wlist command */
+    u_char	closed;
+    u_char	need_reopen;		/* lock-safe change flag */
+} DCC_WF;
+
+extern DCC_WF cmn_wf, cmn_tmp_wf;
+
+typedef enum {				/* greylist result */
+    ASK_GREY_FAIL,			/* greylist server or other failure */
+    ASK_GREY_OFF,			/* client whitelist or blacklist */
+    ASK_GREY_EMBARGO,
+    ASK_GREY_EMBARGO_END,		/* first time server says ok */
+    ASK_GREY_PASS,			/* greylist server says ok */
+    ASK_GREY_WHITE,			/* greylist server says whitelisted */
+    ASK_GREY_SPAM			/* reported as spam to server */
+} ASK_GREY_RESULT;
+
+extern u_char grey_on;
+extern u_char grey_query_only;
+
+extern u_int dcc_ck_qp_decode(DCC_GOT_CKS *, const char **, u_int *,
+			      char *, u_int);
+extern u_int dcc_ck_b64_decode(DCC_GOT_CKS *, const char **, u_int *,
+			       char *, u_int);
+
+extern int dcc_ck_url(DCC_URL_SKIP *, char, char **);
+#define DCC_CK_URL_MASK	    0xff
+#define DCC_CK_URL_SHIFT    8
+typedef enum {
+    DCC_CK_URL_CHAR,			/* character in URL after host name */
+    DCC_CK_URL_CK_LEN,			/* 2nd slash */
+    DCC_CK_URL_HOST,			/* character in URL host name */
+    DCC_CK_URL_DOT,			/* dot in host name */
+    DCC_CK_URL_HOST_END,		/* end of host name */
+    DCC_CK_URL_HOST_RESET,		/* wasn't in host name after all */
+    DCC_CK_URL_SKIP			/* shipping URL or not in URL */
+} DCC_CK_URL;
+
+extern void dcc_ck_fuz1_init(DCC_GOT_CKS *);
+extern void dcc_ck_fuz1(DCC_GOT_CKS *, const char *, u_int);
+extern void dcc_ck_fuz1_fin(DCC_GOT_CKS *);
+
+extern void dcc_ck_fuz2_init(DCC_GOT_CKS *);
+extern void dcc_ck_fuz2(DCC_GOT_CKS *, const char *, u_int);
+extern void dcc_ck_fuz2_fin(DCC_GOT_CKS *);
+
+
+extern void dcc_wf_init(DCC_WF *, u_int);
+extern void dcc_wf_lock(DCC_WF *);
+extern void dcc_wf_unlock(DCC_WF *);
+
+extern void dcc_str2ck(DCC_SUM, const char *, u_int, const char *);
+extern u_char dcc_get_cks(DCC_GOT_CKS *, DCC_CK_TYPES, const char *, u_char);
+extern u_char dcc_ck_get_sub(DCC_GOT_CKS *, const char *, const char *);
+extern u_char dcc_add_sub_hdr(DCC_EMSG, const char *);
+extern void dcc_ck_ipv6(DCC_SUM, const struct in6_addr *);
+extern void dcc_get_ipv6_ck(DCC_GOT_CKS *, const struct in6_addr *);
+extern void dcc_unget_ip_ck(DCC_GOT_CKS *);
+extern u_char dcc_get_str_ip_ck(DCC_GOT_CKS *, const char *);
+extern const char *parse_received(const char *, DCC_GOT_CKS *,
+				  char *, int, char *, int, char *, int);
+extern u_char parse_return_path(const char *,  char *, int);
+extern u_char parse_unix_from(const char *, char *, int);
+extern u_char parse_mail_host(const char *, char *, int);
+extern void dcc_print_cks(LOG_WRITE_FNC, void *, u_char, DCC_TGTS,
+			  const DCC_GOT_CKS *, DCC_CKS_WTGTS, u_char);
+#define PRINT_CK_TYPE_LEN	25
+#define PRINT_CK_SUM_LEN	35
+#define PRINT_CK_PAT_CK		"%25s: %-35s"
+#define PRINT_CK_PAT_LIM_CK	"%25.*s%c %-35.*s"
+#define PRINT_CK_PAT_SRVR	" %7s"
+#define PRINT_CK_PAT_SRVR_LEN   8
+#define PRINT_CK_PAT_WLIST	" %5s"
+#define PRINT_CK_PAT_WLIST_LEN	6
+#define PRINT_CK_PAT_THOLD	PRINT_CK_PAT_WLIST
+
+extern void dcc_cks_init(DCC_GOT_CKS *);
+extern void dcc_ck_mime_hdr(DCC_GOT_CKS *, const char *, const char *);
+extern u_char parse_mime_hdr(DCC_GOT_CKS *, const char *, u_int, u_char);
+extern void dcc_ck_body(DCC_GOT_CKS *, const void *, u_int);
+extern void dcc_cks_fin(DCC_GOT_CKS *);
+
+extern u_char dcc_get_white(DCC_EMSG, DCC_WHITE_INX);
+
+typedef int (*DCC_PARSED_CK_FNC)(DCC_EMSG, DCC_WF *,
+				DCC_CK_TYPES,	/* type of checksum */
+				DCC_SUM,    /* computed checksum */
+				DCC_TGTS);  /* "OK2" etc */
+typedef int (*DCC_PARSED_CK_CIDR_FNC)(DCC_EMSG, DCC_WF *,
+				      int,
+				      const struct in6_addr *,
+				      const struct in6_addr *,
+				      DCC_TGTS);
+extern int dcc_parse_ck(DCC_EMSG, DCC_WF *wf,
+			const char *, DCC_CK_TYPES, const char *, DCC_TGTS,
+			DCC_PARSED_CK_FNC, DCC_PARSED_CK_CIDR_FNC);
+extern int dcc_parse_hex_ck(DCC_EMSG, DCC_WF *wf,
+			    const char *, DCC_CK_TYPES, const char *, DCC_TGTS,
+			    DCC_PARSED_CK_FNC);
+extern const char *wf_fnm(const DCC_WF *, int);
+extern const char *wf_fnm_lno(DCC_FNM_LNO_BUF *, const DCC_WF *);
+extern DCC_TGTS dcc_str2thold(DCC_CK_TYPES, const char *);
+extern int dcc_parse_whitefile(DCC_EMSG, DCC_WF *, int,
+			       DCC_PARSED_CK_FNC, DCC_PARSED_CK_CIDR_FNC);
+
+typedef enum {
+    DCC_WHITE_USE_DCC,
+    DCC_WHITE_LISTED,
+    DCC_WHITE_UNLISTED,
+    DCC_WHITE_BLACK
+} DCC_WHITE_LISTING;
+
+typedef enum {
+    DCC_WHITE_OK,
+    DCC_WHITE_NOFILE,			/* no ASCII file */
+    DCC_WHITE_CONTINUE,			/* modest error or bad host name */
+    DCC_WHITE_COMPLAIN,			/* bad hash table */
+    DCC_WHITE_SILENT			/* no more complaints */
+} DCC_WHITE_RESULT;
+#define DCC_WHITE_RESULT_FAILURE DCC_WHITE_UNLISTED
+
+u_char dcc_new_white_nm(DCC_EMSG, DCC_WF *, const char *);
+extern DCC_WHITE_RESULT dcc_rdy_white(DCC_EMSG, DCC_WF *, DCC_WF *);
+extern DCC_WHITE_RESULT dcc_white_sum(DCC_EMSG, DCC_WF *,
+				      DCC_CK_TYPES, const DCC_SUM,
+				      DCC_TGTS *, DCC_WHITE_LISTING *);
+extern u_char dcc_white_mx(DCC_EMSG, DCC_TGTS *, const DCC_GOT_CKS *);
+extern DCC_WHITE_RESULT dcc_white_cks(DCC_EMSG, DCC_WF *, DCC_GOT_CKS *,
+				      DCC_CKS_WTGTS, DCC_WHITE_LISTING *);
+
+
+typedef u_int32_t ASK_ST;
+#define ASK_ST_INVALID_MSG	0x00000001  /* incomplete SMTP transaction */
+#define	ASK_ST_QUERY		0x00000002  /* ask but do not report */
+#define	ASK_ST_QUERY_GREY	0x00000004
+#define	ASK_ST_SRVR_OK2		0x00000008  /* have honored DCC_TGTS_OK2 */
+#define	ASK_ST_SRVR_NOTSPAM	0x00000010  /* not spam by DCC server */
+#define	ASK_ST_SRVR_ISSPAM	0x00000020  /* spam by DCC server & threshold */
+#define ASK_ST_REP_ISSPAM	0x00000040  /* spam by reputation & threshold */
+#define	ASK_ST_MTA_NOTSPAM	0x00000080  /* MTA says it is not spam */
+#define	ASK_ST_MTA_ISSPAM	0x00000100  /* MTA says it is spam */
+#define	ASK_ST_WLIST_NOTSPAM	0x00000200  /* locally whitelisted message */
+#define	ASK_ST_WLIST_ISSPAM	0x00000400  /* locally blacklisted message */
+#define	ASK_ST_CLNT_ISSPAM	0x00000800  /* report to DCC server as spam */
+#define	ASK_ST_GREY_EMBARGO	0x00001000  /* embargo this message */
+#define	ASK_ST_GREY_LOGIT	0x00002000  /* greylist logging indicated */
+#define	ASK_ST_LOGIT		0x00004000  /* log message for all recipients */
+#define	ASK_ST_DNSBL_HIT(n)    (0x00008000*DNSBL_G2B(n))    /* DNSBL hit */
+# define ASK_ST_DNSBL_HIT_M	0x00038000
+# define ASK_ST_DNSBL_HIT_BITS(st) (((st)&ASK_ST_DNSBL_HIT_M)		    \
+				    / ASK_ST_DNSBL_HIT(0))
+#define	ASK_ST_DNSBL_TIMEO(n)  (0x00040000*DNSBL_G2B(n))    /* DNSBL timeout */
+# define ASK_ST_DNSBL_TIMEO_M	0x001c0000
+# define ASK_ST_DNSBL_TIMEO_BITS(st) (((st)&ASK_ST_DNSBL_TIMEO_M)	    \
+				      / ASK_ST_DNSBL_TIMEO(0))
+#define	ASK_ST_DNSBL_TFAIL(n)  (0x00200000*DNSBL_G2B(n))
+# define ASK_ST_DNSBL_TFAIL_M	0x00e00000
+# define ASK_ST_DNSBL_TFAIL_BITS(st) (((st)&ASK_ST_DNSBL_TFAIL_M)	    \
+				      / ASK_ST_DNSBL_TFAIL(0))
+
+
+extern u_char dcc_ck_grey_answer(DCC_EMSG, const DCC_OP_RESP *);
+extern int ask_dcc(DCC_EMSG, DCC_CLNT_CTXT *, u_char,
+		   DCC_HEADER_BUF *, DCC_GOT_CKS *, ASK_ST *, u_char,
+		   DCC_TGTS);
+extern u_char unthr_ask_white(DCC_EMSG, ASK_ST *, FLTR_SWS *, const char *,
+			      DCC_GOT_CKS *, DCC_CKS_WTGTS);
+extern u_char unthr_ask_dcc(DCC_EMSG, DCC_CLNT_CTXT*, DCC_HEADER_BUF*, ASK_ST *,
+			    DCC_GOT_CKS *, u_char, DCC_TGTS);
+extern void dcc_clear_tholds(void);
+extern u_char dcc_merge_tholds(DCC_CKSUM_THOLDS,
+			       const DCC_CKSUM_THOLDS, const DCC_WHITE_TBL *);
+extern void dcc_parse_honor(const char *);
+extern u_char dcc_parse_tholds(const char *, const char *);
+extern void dcc_honor_log_cnts(ASK_ST *, const DCC_GOT_CKS *, DCC_TGTS);
+extern FLTR_SWS wf2sws(FLTR_SWS, const DCC_WF *);
+extern void log_ask_st(LOG_WRITE_FNC, void *, ASK_ST, FLTR_SWS, u_char,
+		       const DCC_HEADER_BUF *);
+extern u_char dcc_parse_client_grey(const char *);
+extern ASK_GREY_RESULT ask_grey(DCC_EMSG, DCC_CLNT_CTXT *, DCC_OPS,
+				DCC_SUM, DCC_SUM,
+				const DCC_GOT_CKS *, const DCC_SUM,
+				DCC_TGTS *, DCC_TGTS *, DCC_TGTS *);
+
+extern u_char dcc_parse_dnsbl(DCC_EMSG, const char *, const char *, u_char);
+extern const REPLY_TPLT *dnsbl_parse_reply(const char *);
+extern void helper_save_arg(const char *, const char *);
+extern void helper_init(int);
+extern void dcc_dnsbl_init(DCC_GOT_CKS *,
+			   DCC_CLNT_CTXT *, void *, const char *);
+extern void url_dnsbl(DNSBL_WORK *);
+extern void dcc_mail_host_dnsbl(DNSBL_WORK *, const char *);
+extern void dcc_client_dnsbl(DNSBL_WORK *, const struct in6_addr *,
+			     const char *);
+extern void dcc_dnsbl_result(ASK_ST *, DNSBL_WORK *);
+extern int PATTRIB(3,4) thr_log_print(void *, u_char, const char *, ...);
+extern int PATTRIB(2,3) thr_error_msg(void *, const char *, ...);
+extern void PATTRIB(2,3) thr_trace_msg(void *, const char *, ...);
+
+#endif /* DCC_CK_H */