Sophie

Sophie

distrib > Mandriva > 2011.0 > i586 > media > contrib-release-debug > by-pkgid > 95e1486a8650430c9f01849aff7a09a2 > files > 104

dcc-debug-1.3.122-2mdv2011.0.i586.rpm

/* Distributed Checksum Clearinghouse
 *
 * checksum routines
 *
 * Copyright (c) 2009 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.122-1.193 $Revision$
 */

#ifndef DCC_CK_H
#define DCC_CK_H

#include "dcc_clnt.h"
#include "dcc_md5.h"


typedef struct {
    DCC_TGTS	t[DCC_DIM_CKS];
} DCC_CKSUM_THOLDS;
#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	    DCC_MAXDOMAINLEN
#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_CLIENT	    0x04	/* check client IP address */
#define	DNSBL_FG_MAIL_HOST  0x08	/* check env_from domain */
#define	DNSBL_FG_URL	    0x10	/* check URLs in message body */
# define DNSBL_FG_HITS	    (DNSBL_FG_CLIENT | DNSBL_FG_MAIL_HOST | DNSBL_FG_URL)
#define	DNSBL_FG_MX	    0x20	/* MX for _URL & _MAIL_HOST */
#define	DNSBL_FG_NS	    0x40	/* NS for _URL & _MAIL_HOST */
# define DNSBL_FG_TYPES	    (DNSBL_FG_HITS | DNSBL_FG_MX | DNSBL_FG_NS)

typedef enum DNSBL_TYPE {
    DNSBL_TYPE_IPV4,
    DNSBL_TYPE_IPV6,
    DNSBL_TYPE_NAME,
    DNSBL_TYPE_ALL_NAMES
} DNSBL_TYPE;

#define	NUM_DNSBL_GROUPS    3
typedef u_char	DNSBL_GBITS;
#define DNSBL_GMASK  ((2<<NUM_DNSBL_GROUPS)-1)
#define DNSBL_G2B(n) ((1<<(n)) & DNSBL_GMASK)

typedef struct dnsbl {
    struct dnsbl *fwd;
    struct dnsbl *dup;			/* same except result */
    u_char	group;			/* 1-indexed */
    DCC_IP_RANGE tgt;			/* hit if DNSBL matches this range */
    DCC_GETH	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[NUM_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_FUZ1_BUF_MAX (DCC_FUZ1_MAX_LINE*4)	/* >DCC_MAXDOMAINLEN */
#    define	 DCC_HTTPS_STR	    "https"
#    define	 DCC_HTTPS_LEN	    LITZ(DCC_HTTPS_STR)
    char	buf[DCC_FUZ1_BUF_MAX+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_LANG_NUM (DCC_LANG_ENGLISH+DCC_LANG_SPANISH		\
			   +DCC_LANG_POLISH+DCC_LANG_DUTCH)
    FUZ2_LANG	lang[FUZ2_LANG_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 struct {
    DCC_TGTS v[DCC_WSUMS];
} DCC_CKS_WTGTS;


/* 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 "25"

typedef struct {
    DCC_IP_RANGE range;
    DCC_TGTS	tgts;
    u_int	len;
    u_short	lno;
    u_char	fno;
} DCC_WHITE_RANGE;

typedef struct {
    u_char	len;
#    define	 WHITE_RANGES_MAX 64	/* fix dcc.man if this changes */
    DCC_WHITE_RANGE rs[WHITE_RANGES_MAX];
} DCC_WHITE_RANGES;

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_HAVE_THOLDS   0x00000002	/* have some */
#	 define	 DCC_WHITE_FG_HOSTNAMES	    0x00000004	/* have some */
#	 define	 DCC_WHITE_FG_GREY_LOG_ON   0x00000008
#	 define	 DCC_WHITE_FG_GREY_LOG_OFF  0x00000010
#	 define	 DCC_WHITE_FG_GREY_ON	    0x00000020
#	 define	 DCC_WHITE_FG_GREY_OFF	    0x00000040
#	 define	 DCC_WHITE_FG_LOG_ALL	    0x00000080
#	 define	 DCC_WHITE_FG_LOG_NORMAL    0x00000100
#	 define	 DCC_WHITE_FG_DISCARD_OK    0x00000200
#	 define	 DCC_WHITE_FG_NO_DISCARD    0x00000400
#	 define	 DCC_WHITE_FG_DCC_ON	    0x00000800
#	 define	 DCC_WHITE_FG_DCC_OFF	    0x00001000
#	 define	 DCC_WHITE_FG_REP_ON	    0x00002000
#	 define	 DCC_WHITE_FG_REP_OFF	    0x00004000
#	 define	 DCC_WHITE_FG_MTA_FIRST	    0x00008000
#	 define	 DCC_WHITE_FG_MTA_LAST	    0x00010000
#	 define	 DCC_WHITE_FG_LOG_D	    0x00020000
#	 define	 DCC_WHITE_FG_LOG_H	    0x00040000
#	 define	 DCC_WHITE_FG_LOG_M	    0x00080000
#	 define	 DCC_WHITE_FG_TRAP_NOT	    0x00100000	/* not a spam trap */
#	 define	 DCC_WHITE_FG_TRAP_DIS	    0x00200000	/* discard spam trap */
#	 define	 DCC_WHITE_FG_TRAP_REJ	    0x00400000	/* reject spam trap */
#	  define  DCC_WHITE_FG_TRAPS (DCC_WHITE_FG_TRAP_DIS		\
				      | DCC_WHITE_FG_TRAP_REJ)
#	 define  DCC_WHITE_FG_DNSBL_ON(n)  (0x00800000*DNSBL_G2B(n))
#	 define  DCC_WHITE_FG_DNSBL_ON_M   (DCC_WHITE_FG_DNSBL_ON(0)	\
					    * DNSBL_GMASK)
#	 define	 DCC_WHITE_FG_DNSBL_OFF(n) (0x04000000*DNSBL_G2B(n))
#	 define	 DCC_WHITE_FG_SET   (~(DCC_WHITE_FG_PER_USER		\
				       | DCC_WHITE_FG_HOSTNAMES))
	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_RANGES ranges;
    } 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		0x00000800  /* either type of trap */
#define	FLTR_SW_TRAP_DIS	0x00001000  /* discarding spam trap */
#define	FLTR_SW_TRAP_REJ	0x00002000  /* rejecting spam trap */
#define	FLTR_SW_DNSBL(n)       (0x00004000*DNSBL_G2B(n))
# define FLTR_SW_DNSBL_M	(FLTR_SW_DNSBL(0) * DNSBL_GMASK)
# define FLTR_SW_DNSBL_BITS(sws) (((sws) / FLTR_SW_DNSBL(0)) & DNSBL_GMASK)

/* bits set to enable filtering */
#define FLTR_SWS_FILTER_ON  (FLTR_SW_REP_ON				\
			     | FLTR_SW_MTA_FIRST			\
			     | FLTR_SW_DNSBL_M				\
			     | FLTR_SW_TRAP_DIS				\
			     | FLTR_SW_TRAP_REJ				\
			     | FLTR_SW_TRAP)
/* bits set to disable filtering */
#define FLTR_SWS_FILTER_OFF (FLTR_SW_DCC_OFF				\
			     | FLTR_SW_NO_DISCARD			\
			     | FLTR_SW_GREY_OFF)
/* get bits of enabled and disabled FILTERS */
#define FLTR_SWS_FLTRS(sws) ((sws) & (FLTR_SW_DCC_OFF			\
				      | FLTR_SW_GREY_OFF		\
				      | FLTR_SW_MTA_FIRST		\
				      | FLTR_SW_REP_ON			\
				      | FLTR_SW_DNSBL_M			\
				      | FLTR_SW_TRAP_DIS		\
				      | FLTR_SW_TRAP_REJ		\
				      | FLTR_SW_TRAP))


/* 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 str2ck(DCC_SUM, const char *, u_int, const char *);
extern u_char get_cks(DCC_GOT_CKS *, DCC_CK_TYPES, const char *, u_char);
extern u_char ck_get_sub(DCC_GOT_CKS *, const char *, const char *);
extern u_char dcc_add_sub_hdr(DCC_EMSG, const char *);
extern void ipv6tock(DCC_SUM, const struct in6_addr *);
extern void get_ipv6_ck(DCC_GOT_CKS *, const struct in6_addr *);
extern void no_ip_rpt2srvr(DCC_GOT_CKS *);
extern void unget_body_ck(DCC_GOT_CKS *);
extern u_char str2ipck(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 *, const DCC_CKSUM_THOLDS *,
			  const DCC_CKS_WTGTS *);
#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_RANGE_FNC)(DCC_EMSG, DCC_WF *,
				       const DCC_IP_RANGE *, 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_RANGE_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 parse_whitefile(DCC_EMSG, DCC_WF *, int,
			   DCC_PARSED_CK_FNC, DCC_PARSED_CK_RANGE_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

extern u_char dcc_new_white_nm(DCC_EMSG, DCC_WF *, const char *);
extern u_char new_ht_nm(DCC_EMSG, DCC_WF *, u_char);
extern int unlink_white_ht(DCC_EMSG, DCC_WF *, time_t);
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))


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 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 *);
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 DCC_PF(3,4) thr_log_print(void *, u_char, const char *, ...);
extern int DCC_PF(2,3) thr_error_msg(void *, const char *, ...);
extern void DCC_PF(2,3) thr_trace_msg(void *, const char *, ...);

#endif /* DCC_CK_H */