view src/context.h @ 192:8f4a9a37d4d9

delay autowhitelisting to avoid out of office reply bots
author carl
date Sun, 11 Nov 2007 12:49:25 -0800
parents 8b86a894514d
children 82886d4dd71f
line wrap: on
line source

/*

Copyright (c) 2007 Carl Byington - 510 Software Group, released under
the GPL version 3 or any later version at your choice available at
http://www.gnu.org/licenses/gpl-3.0.txt

*/

#ifndef context_include
#define context_include

#include "tokenizer.h"
#include <map>
#include <regex.h>


enum status {oksofar,		// not rejected yet
			 white, 		// whitelisted
			 black, 		// blacklisted
			 reject};		// rejected by a dns list

class DNSBL;
class CONTEXT;
class VERIFY;
class SMTP;
class WHITELISTER;
class DELAYWHITE;
class recorder;

typedef map<char *, char *, ltstr>		  string_map;
typedef set<int>						  int_set;
typedef list<SMTP *>					  smtp_list;
typedef list<char *>					  string_list;
typedef DNSBL * 						  DNSBLP;
typedef VERIFY *						  VERIFYP;
typedef WHITELISTER *					  WHITELISTERP;
typedef DELAYWHITE *                      DELAYWHITEP;
typedef list<DNSBLP>					  dnsblp_list;
typedef map<char *, DNSBLP, ltstr>		  dnsblp_map;
typedef CONTEXT *						  CONTEXTP;
typedef list<CONTEXTP>					  context_list;
typedef map<char *, CONTEXTP, ltstr>	  context_map;
typedef map<char *, int, ltstr> 		  ns_mapper;
typedef map<char *, int, ltstr> 		  rcpt_rates;
typedef map<char *, time_t,  ltstr> 	  autowhite_sent;
typedef map<char *, VERIFYP, ltstr> 	  verify_map;
typedef map<char *, WHITELISTERP, ltstr>  whitelister_map;
typedef list<DELAYWHITEP>                 delay_whitelist;

class SMTP {
	static const int maxlen = 1000;
	int 	fd;
	bool	error;
	time_t	stamp;
	char	efrom[maxlen];	// last envelope from sent on this socket
	int 	pending;		// unread bytes in buffer, not including the null terminator
	char	buffer[maxlen];
public:
	SMTP(int f) 			{fd = f; error = false; now(); efrom[0] = '\0'; init();};
	~SMTP() 				{if (!error) quit(); closefd();};
	void	init()			{pending = 0; buffer[0] = '\0';};
	void	append(char *c) {strncat(buffer, c, max(0, maxlen-1-(int)strlen(c)));};
	bool	err()			{return error;};
	void	now()			{stamp = time(NULL);};
	time_t	get_stamp() 	{return stamp;};
	int 	get_fd()		{return fd;};
	int 	writer();
	int 	reader();
	int 	read_line();
	int 	read_response();
	void	flush_line(int r);
	int 	cmd(char *c);
	int 	helo();
	int 	rset();
	int 	from(char *f);
	int 	rcpt(char *t);
	int 	quit();
	void	closefd();
#ifdef VERIFY_DEBUG
	static void log(char *m, int v);
	static void log(char *m, char *v);
#endif
};

class VERIFY {
	char			*host;		// host to be used to verify recipient addresses
	time_t			last_err;	// time of last socket error
	pthread_mutex_t mutex;		// protect the lists of sockets and timestamps
	smtp_list		connections;// open sockets, ready to be used
public:
	VERIFY(char *h);
	void	closer();			// if the oldest socket is ancient, close it
	SMTP	*get_connection();
	void	put_connection(SMTP *conn);
	bool	ok(char *from, char *to);
};

class WHITELISTER {
	char			*fn;		// file to use
	int 			days;		// how long do we keep entries
	pthread_mutex_t mutex;		// protect the flag and map
	time_t			loaded; 	// when we loaded this file
	bool			need;		// force writing on new entries
	autowhite_sent	rcpts;		// recipient map to remember when we sent them mail
public:
	WHITELISTER(char *f, int d);
	void	merge();
	void	writer();			// dump any changes back to the file
	void	sent(char *to);
	bool	is_white(char *from);	// should we white list this sender (did we send them anything recently)
	int 	get_days()		{return days;};
	void	set_days(int d) {days = d;};
};

class DELAYWHITE {
    char*           loto;
    WHITELISTERP    w;
    CONTEXTP        con;
public:
    DELAYWHITE(char *loto_, WHITELISTERP w_, CONTEXTP con_);
    char           *get_loto() {return loto;};
    WHITELISTERP    get_w()    {return w;};
    CONTEXTP        get_con()  {return con;};
};

struct DNSBL {
	char	*name;		// nickname for this dns based list
	char	*suffix;	// blacklist suffix like blackholes.five-ten-sg.com
	char	*message;	// error message with one or two %s operators for the ip address replacement
	DNSBL(char *n, char *s, char *m);
	bool operator==(const DNSBL &rhs);
};

class CONTEXT {
	CONTEXTP		parent;
	char *			name;
	context_map 	children;			// map child context names to their contexts
	string_set		env_to; 			// this context applies to these envelope recipients
	char *			verify_host;		// use this smtp host to verify email addresses
	VERIFYP 		verifier;			// pointer to the verifier structure
	char *			generic_regx;		// pointer to generic regular expression
	char *			generic_message;	// pointer to generic message with one %s
	regex_t 		generic_pattern;	// compiled regex pattern
	char *			autowhite_file; 	// file to use for automatic whitelisting
	WHITELISTERP	whitelister;		// pointer to the auto whitelister structure
	string_map		env_from;			// map senders to white/black/unknown
	context_map 	env_from_context;	// map senders to a child context
	char *			env_from_default;	// default value for senders that are not found in the map white/black/unknown/inherit
	bool			content_filtering;	//
	char *			content_suffix; 	// for url body filtering based on ip addresses of hostnames in the body
	char *			content_message;	// ""
	char *			uribl_suffix;		// for uribl body filtering based on hostnames in the body
	char *			uribl_message;		// ""
	string_set		content_host_ignore;// hosts to ignore for content sbl checking
	string_set		content_tlds;		//
	string_set		content_cctlds; 	//
	string_set		html_tags;			// set of valid html tags
	int 			host_limit; 		// limit on host names
	char *			host_limit_message; // error message for excessive host names
	bool			host_random;		// pick a random selection of host names rather than error for excessive hosts
	int 			tag_limit;			// limit on bad html tags
	char *			tag_limit_message;	// error message for excessive bad html tags
	int 			spamassassin_limit; // max score from spamassassin
	bool			require_match;		// require matching context filtering context
	bool			dcc_greylist;		// should we do dcc greylisting?
	int 			dcc_bulk_threshold; // off = 0, many = 1000
	dnsblp_map		dnsbl_names;		// name to dnsbl mapping for lists that are available in this context and children
	dnsblp_list 	dnsbl_list; 		// list of dnsbls to be used in this context
	int 			default_rcpt_rate;	// if not specified per user
	rcpt_rates		rcpt_per_hour;		// per user limits on number of recipients per hour


public:
	CONTEXT(CONTEXTP parent_, char *name_);
	~CONTEXT();
	CONTEXTP	get_parent()								{return parent;};
	bool		is_parent(CONTEXTP p);		// is p a parent of this?
	char*		get_full_name(char *buf, int size);
	void		add_context(CONTEXTP child) 				{children[child->name] = child;};
	bool		allow_env_to(char *to)						{return (parent) ? parent->cover_env_to(to) : true;};
	bool		cover_env_to(char *to);

	void		set_verifier(VERIFYP v) 					{verifier	 = v;};
	void		set_verify(char *host)						{verify_host = host;};
	char*		get_verify()								{return verify_host;};
	VERIFYP 	find_verify(char *to);


	void		set_whitelister(WHITELISTERP v) 			{whitelister	= v;};
	void		set_autowhite(char *fn) 					{autowhite_file = fn;};
	char*		get_autowhite() 							{return autowhite_file;};
	WHITELISTERP find_autowhite(char *from, char *to);

	void		set_default_rate(int limit) 				{default_rcpt_rate	 = limit;};
	void		add_rate(char *user, int limit) 			{rcpt_per_hour[user] = limit;};
	int 		find_rate(char *user);

	void		add_to(char *to)							{env_to.insert(to);};
	void		add_from(char *from, char *status)			{env_from[from] = status;};
	void		add_from_context(char *from, CONTEXTP con)	{env_from_context[from] = con;};
	void		set_from_default(char *status)				{env_from_default = status;};
	char*		find_from(char *from, bool update_white = false);
	CONTEXTP	find_context(char *from);
	CONTEXTP	find_from_context_name(char *name);

	void		set_content_filtering(bool filter)			{content_filtering = filter;	  };
	void		set_content_suffix(char *suffix)			{content_suffix    = suffix;	  };
	void		set_content_message(char *message)			{content_message   = message;	  };
	void		set_uribl_suffix(char *suffix)				{uribl_suffix	   = suffix;	  };
	void		set_uribl_message(char *message)			{uribl_message	   = message;	  };
	void		add_ignore(char *host)						{content_host_ignore.insert(host);};
	void		add_tld(char *tld)							{content_tlds.insert(tld);		  };
	void		add_cctld(char *cctld)						{content_cctlds.insert(cctld);	  };

	void		set_host_limit(int limit)					{host_limit 		= limit;  };
	void		set_host_message(char *message) 			{host_limit_message = message;};
	void		set_host_random(bool random)				{host_random		= random; };
	void		set_spamassassin_limit(int limit)			{spamassassin_limit = limit;  };
	void		set_tag_limit(int limit)					{tag_limit			= limit;  };
	void		set_tag_message(char *message)				{tag_limit_message	= message;};
	void		add_tag(char *tag)							{html_tags.insert(tag); 	  };

	void		add_dnsbl(char *name, DNSBLP dns)			{dnsbl_names[name] = dns;  };
	void		add_dnsbl(DNSBLP dns)						{dnsbl_list.push_back(dns);};
	DNSBLP		find_dnsbl(char *name);

	bool		set_generic(char *regx, char *msg);
	char*		generic_match(char *client);

	void		set_require(bool r) 						{require_match		= r; };
	void		set_grey(bool g)							{dcc_greylist		= g; };
	void		set_bulk(int b) 							{dcc_bulk_threshold = b; };

	bool			get_content_filtering() 				{return content_filtering; };
	bool			get_require()							{return content_filtering && require_match; 	};
	bool			get_grey()								{return content_filtering && dcc_greylist;		};
	int 			get_bulk()								{return (content_filtering) ? dcc_bulk_threshold : 0;};
	int 			get_host_limit()						{return (content_filtering) ? host_limit		 : 0;};
	bool			get_host_random()						{return (content_filtering) ? host_random		 : 0;};
	int 			get_spamassassin_limit()				{return (content_filtering) ? spamassassin_limit : 0;};
	char*			get_content_suffix();
	char*			get_content_message();
	char*			get_uribl_suffix();
	char*			get_uribl_message();
	string_set& 	get_content_host_ignore();
	string_set& 	get_content_tlds();
	string_set& 	get_content_cctlds();
	string_set& 	get_html_tags();
	dnsblp_list&	get_dnsbl_list();

	bool		acceptable_content(recorder &memory, int score, int bulk, string& msg);
	bool		ignore_host(char *host);

	void		dump(bool isdefault, bool &spamass, int level = 0);
};


struct CONFIG {
	// the only mutable stuff once it has been loaded from the config file
	int 		reference_count;	// protected by the global config_mutex
	// all the rest is constant after loading from the config file
	int 			generation;
	time_t			load_time;
	string_set		config_files;
	context_list	contexts;		// owns all the contexts, not just top level contexts
	context_map 	env_to; 		// map recipient to a filtering context
	CONTEXTP		default_context;// for env_to values that don't have their own specific filtering context
	// the default context is also used for some of the content filtering values

	CONFIG();
	~CONFIG();
	void		add_context(CONTEXTP con);
	void		add_to(char *to, CONTEXTP con);
	CONTEXTP	find_context(char *to);
	void		dump();
};


extern char *token_autowhite;
extern char *token_black;
extern char *token_cctld;
extern char *token_content;
extern char *token_context;
extern char *token_dccbulk;
extern char *token_dccfrom;
extern char *token_dccgrey;
extern char *token_dccto;
extern char *token_default;
extern char *token_dnsbl;
extern char *token_dnsbll;
extern char *token_envfrom;
extern char *token_envto;
extern char *token_filter;
extern char *token_generic;
extern char *token_host_limit;
extern char *token_html_limit;
extern char *token_html_tags;
extern char *token_ignore;
extern char *token_include;
extern char *token_inherit;
extern char *token_lbrace;
extern char *token_mailhost;
extern char *token_many;
extern char *token_no;
extern char *token_off;
extern char *token_ok;
extern char *token_ok2;
extern char *token_on;
extern char *token_rate;
extern char *token_rbrace;
extern char *token_require;
extern char *token_semi;
extern char *token_soft;
extern char *token_spamassassin;
extern char *token_substitute;
extern char *token_tld;
extern char *token_unknown;
extern char *token_uribl;
extern char *token_verify;
extern char *token_white;
extern char *token_yes;

extern pthread_mutex_t verifier_mutex;	   // protect the verifier map
extern pthread_mutex_t whitelister_mutex;  // protect the

void discard(string_set &s);
char* register_string(string_set &s, char *name);
char* register_string(char *name);
void  clear_strings();
CONFIG *parse_config(char *fn);
bool  load_conf(CONFIG &dc, char *fn);
void* verify_closer(void *arg);
void* whitelister_writer(void *arg);
void  token_init();

#endif