xref: /plan9/sys/src/cmd/upas/smtp/spam.c (revision c6569576083e48cef148efbb162a33bacec4ce98)
17dd7cddfSDavid du Colombier #include "common.h"
27dd7cddfSDavid du Colombier #include "smtpd.h"
3e288d156SDavid du Colombier #include <ip.h>
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier enum {
67dd7cddfSDavid du Colombier 	NORELAY = 0,
77dd7cddfSDavid du Colombier 	DNSVERIFY,
87dd7cddfSDavid du Colombier 	SAVEBLOCK,
97dd7cddfSDavid du Colombier 	DOMNAME,
107dd7cddfSDavid du Colombier 	OURNETS,
117dd7cddfSDavid du Colombier 	OURDOMS,
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier 	IP = 0,
147dd7cddfSDavid du Colombier 	STRING,
157dd7cddfSDavid du Colombier };
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier typedef struct Keyword Keyword;
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier struct Keyword {
217dd7cddfSDavid du Colombier 	char	*name;
227dd7cddfSDavid du Colombier 	int	code;
237dd7cddfSDavid du Colombier };
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier static Keyword options[] = {
267dd7cddfSDavid du Colombier 	"norelay",		NORELAY,
277dd7cddfSDavid du Colombier 	"verifysenderdom",	DNSVERIFY,
287dd7cddfSDavid du Colombier 	"saveblockedmsg",	SAVEBLOCK,
297dd7cddfSDavid du Colombier 	"defaultdomain",	DOMNAME,
307dd7cddfSDavid du Colombier 	"ournets",		OURNETS,
317dd7cddfSDavid du Colombier 	"ourdomains",		OURDOMS,
327dd7cddfSDavid du Colombier 	0,			NONE,
337dd7cddfSDavid du Colombier };
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier static Keyword actions[] = {
367dd7cddfSDavid du Colombier 	"allow",		ACCEPT,
377dd7cddfSDavid du Colombier 	"block",		BLOCKED,
387dd7cddfSDavid du Colombier 	"deny",			DENIED,
397dd7cddfSDavid du Colombier 	"dial",			DIALUP,
4080ee5cbfSDavid du Colombier 	"delay",		DELAY,
417dd7cddfSDavid du Colombier 	0,			NONE,
427dd7cddfSDavid du Colombier };
437dd7cddfSDavid du Colombier 
449a747e4fSDavid du Colombier static	int	hisaction;
45e288d156SDavid du Colombier static	List	ourdoms;
46e288d156SDavid du Colombier static	List 	badguys;
47e288d156SDavid du Colombier static	ulong	v4peerip;
489a747e4fSDavid du Colombier 
497dd7cddfSDavid du Colombier static	char*	getline(Biobuf*);
50e288d156SDavid du Colombier static	int	cidrcheck(char*);
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier static int
findkey(char * val,Keyword * p)537dd7cddfSDavid du Colombier findkey(char *val, Keyword *p)
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier 	for(; p->name; p++)
577dd7cddfSDavid du Colombier 		if(strcmp(val, p->name) == 0)
587dd7cddfSDavid du Colombier 				break;
597dd7cddfSDavid du Colombier 	return p->code;
607dd7cddfSDavid du Colombier }
617dd7cddfSDavid du Colombier 
629a747e4fSDavid du Colombier char*
actstr(int a)639a747e4fSDavid du Colombier actstr(int a)
649a747e4fSDavid du Colombier {
650b9a5132SDavid du Colombier 	static char buf[32];
669a747e4fSDavid du Colombier 	Keyword *p;
679a747e4fSDavid du Colombier 
689a747e4fSDavid du Colombier 	for(p=actions; p->name; p++)
699a747e4fSDavid du Colombier 		if(p->code == a)
709a747e4fSDavid du Colombier 			return p->name;
719a747e4fSDavid du Colombier 	if(a==NONE)
729a747e4fSDavid du Colombier 		return "none";
739a747e4fSDavid du Colombier 	sprint(buf, "%d", a);
749a747e4fSDavid du Colombier 	return buf;
759a747e4fSDavid du Colombier }
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier int
getaction(char * s,char * type)789a747e4fSDavid du Colombier getaction(char *s, char *type)
799a747e4fSDavid du Colombier {
809a747e4fSDavid du Colombier 	char buf[1024];
819a747e4fSDavid du Colombier 	Keyword *k;
829a747e4fSDavid du Colombier 
839a747e4fSDavid du Colombier 	if(s == nil || *s == 0)
849a747e4fSDavid du Colombier 		return ACCEPT;
859a747e4fSDavid du Colombier 
869a747e4fSDavid du Colombier 	for(k = actions; k->name != 0; k++){
879a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "/mail/ratify/%s/%s/%s", k->name, type, s);
889a747e4fSDavid du Colombier 		if(access(buf,0) >= 0)
899a747e4fSDavid du Colombier 			return k->code;
909a747e4fSDavid du Colombier 	}
919a747e4fSDavid du Colombier 	return ACCEPT;
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier int
istrusted(char * s)959a747e4fSDavid du Colombier istrusted(char *s)
969a747e4fSDavid du Colombier {
979a747e4fSDavid du Colombier 	char buf[1024];
989a747e4fSDavid du Colombier 
999a747e4fSDavid du Colombier 	if(s == nil || *s == 0)
1009a747e4fSDavid du Colombier 		return 0;
1019a747e4fSDavid du Colombier 
1029a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "/mail/ratify/trusted/%s", s);
1039a747e4fSDavid du Colombier 	return access(buf,0) >= 0;
1049a747e4fSDavid du Colombier }
1059a747e4fSDavid du Colombier 
1067dd7cddfSDavid du Colombier void
getconf(void)1077dd7cddfSDavid du Colombier getconf(void)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier 	Biobuf *bp;
1107dd7cddfSDavid du Colombier 	char *cp, *p;
1117dd7cddfSDavid du Colombier 	String *s;
1127dd7cddfSDavid du Colombier 	char buf[512];
113e288d156SDavid du Colombier 	uchar addr[4];
114e288d156SDavid du Colombier 
115e288d156SDavid du Colombier 	v4parseip(addr, nci->rsys);
116e288d156SDavid du Colombier 	v4peerip = nhgetl(addr);
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier 	trusted = istrusted(nci->rsys);
1199a747e4fSDavid du Colombier 	hisaction = getaction(nci->rsys, "ip");
1209a747e4fSDavid du Colombier 	if(debug){
1219a747e4fSDavid du Colombier 		fprint(2, "istrusted(%s)=%d\n", nci->rsys, trusted);
1229a747e4fSDavid du Colombier 		fprint(2, "getaction(%s, ip)=%s\n", nci->rsys, actstr(hisaction));
12380ee5cbfSDavid du Colombier 	}
1247dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s/smtpd.conf", UPASLIB);
1257dd7cddfSDavid du Colombier 	bp = sysopen(buf, "r", 0);
1267dd7cddfSDavid du Colombier 	if(bp == 0)
1277dd7cddfSDavid du Colombier 		return;
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier 	for(;;){
1307dd7cddfSDavid du Colombier 		cp = getline(bp);
1317dd7cddfSDavid du Colombier 		if(cp == 0)
1327dd7cddfSDavid du Colombier 			break;
1337dd7cddfSDavid du Colombier 		p = cp+strlen(cp)+1;
1347dd7cddfSDavid du Colombier 		switch(findkey(cp, options)){
1357dd7cddfSDavid du Colombier 		case NORELAY:
1367dd7cddfSDavid du Colombier 			if(fflag == 0 && strcmp(p, "on") == 0)
1377dd7cddfSDavid du Colombier 				fflag++;
1387dd7cddfSDavid du Colombier 			break;
1397dd7cddfSDavid du Colombier 		case DNSVERIFY:
1407dd7cddfSDavid du Colombier 			if(rflag == 0 && strcmp(p, "on") == 0)
1417dd7cddfSDavid du Colombier 				rflag++;
1427dd7cddfSDavid du Colombier 			break;
1437dd7cddfSDavid du Colombier 		case SAVEBLOCK:
1447dd7cddfSDavid du Colombier 			if(sflag == 0 && strcmp(p, "on") == 0)
1457dd7cddfSDavid du Colombier 				sflag++;
1467dd7cddfSDavid du Colombier 			break;
1477dd7cddfSDavid du Colombier 		case DOMNAME:
1487dd7cddfSDavid du Colombier 			if(dom == 0)
1497dd7cddfSDavid du Colombier 				dom = strdup(p);
1507dd7cddfSDavid du Colombier 			break;
1517dd7cddfSDavid du Colombier 		case OURNETS:
1527dd7cddfSDavid du Colombier 			if (trusted == 0)
1537dd7cddfSDavid du Colombier 				trusted = cidrcheck(p);
1547dd7cddfSDavid du Colombier 			break;
1557dd7cddfSDavid du Colombier 		case OURDOMS:
1567dd7cddfSDavid du Colombier 			while(*p){
1577dd7cddfSDavid du Colombier 				s = s_new();
1587dd7cddfSDavid du Colombier 				s_append(s, p);
1597dd7cddfSDavid du Colombier 				listadd(&ourdoms, s);
1607dd7cddfSDavid du Colombier 				p += strlen(p)+1;
1617dd7cddfSDavid du Colombier 			}
1627dd7cddfSDavid du Colombier 			break;
1637dd7cddfSDavid du Colombier 		default:
1647dd7cddfSDavid du Colombier 			break;
1657dd7cddfSDavid du Colombier 		}
1667dd7cddfSDavid du Colombier 	}
1677dd7cddfSDavid du Colombier 	sysclose(bp);
1687dd7cddfSDavid du Colombier }
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier /*
1717dd7cddfSDavid du Colombier  *	match a user name.  the only meta-char is '*' which matches all
1727dd7cddfSDavid du Colombier  *	characters.  we only allow it as "*", which matches anything or
1737dd7cddfSDavid du Colombier  *	an * at the end of the name (e.g., "username*") which matches
1747dd7cddfSDavid du Colombier  *	trailing characters.
1757dd7cddfSDavid du Colombier  */
1767dd7cddfSDavid du Colombier static int
usermatch(char * pathuser,char * specuser)1777dd7cddfSDavid du Colombier usermatch(char *pathuser, char *specuser)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier 	int n;
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	n = strlen(specuser)-1;
1827dd7cddfSDavid du Colombier 	if(specuser[n] == '*'){
1837dd7cddfSDavid du Colombier 		if(n == 0)		/* match everything */
1847dd7cddfSDavid du Colombier 			return 0;
1857dd7cddfSDavid du Colombier 		return strncmp(pathuser, specuser, n);
1867dd7cddfSDavid du Colombier 	}
1877dd7cddfSDavid du Colombier 	return strcmp(pathuser, specuser);
1887dd7cddfSDavid du Colombier }
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier static int
dommatch(char * pathdom,char * specdom)1917dd7cddfSDavid du Colombier dommatch(char *pathdom, char *specdom)
1927dd7cddfSDavid du Colombier {
1937dd7cddfSDavid du Colombier 	int n;
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier 	if (*specdom == '*'){
1967dd7cddfSDavid du Colombier 		if (specdom[1] == '.' && specdom[2]){
1977dd7cddfSDavid du Colombier 			specdom += 2;
1987dd7cddfSDavid du Colombier 			n = strlen(pathdom)-strlen(specdom);
1997dd7cddfSDavid du Colombier 			if(n == 0 || (n > 0 && pathdom[n-1] == '.'))
2007dd7cddfSDavid du Colombier 				return strcmp(pathdom+n, specdom);
2017dd7cddfSDavid du Colombier 			return n;
2027dd7cddfSDavid du Colombier 		}
2037dd7cddfSDavid du Colombier 	}
2047dd7cddfSDavid du Colombier 	return strcmp(pathdom, specdom);
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier /*
2089a747e4fSDavid du Colombier  *  figure out action for this sender
2097dd7cddfSDavid du Colombier  */
2107dd7cddfSDavid du Colombier int
blocked(String * path)2117dd7cddfSDavid du Colombier blocked(String *path)
2127dd7cddfSDavid du Colombier {
2139a747e4fSDavid du Colombier 	String *lpath;
2149a747e4fSDavid du Colombier 	int action;
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier 	if(debug)
2177dd7cddfSDavid du Colombier 		fprint(2, "blocked(%s)\n", s_to_c(path));
2187dd7cddfSDavid du Colombier 
2199a747e4fSDavid du Colombier 	/* if the sender's IP address is blessed, ignore sender email address */
2209a747e4fSDavid du Colombier 	if(trusted){
2219a747e4fSDavid du Colombier 		if(debug)
2229a747e4fSDavid du Colombier 			fprint(2, "\ttrusted => trusted\n");
2239a747e4fSDavid du Colombier 		return TRUSTED;
2247dd7cddfSDavid du Colombier 	}
2257dd7cddfSDavid du Colombier 
2269a747e4fSDavid du Colombier 	/* if sender's IP address is blocked, ignore sender email address */
2279a747e4fSDavid du Colombier 	if(hisaction != ACCEPT){
2289a747e4fSDavid du Colombier 		if(debug)
2299a747e4fSDavid du Colombier 			fprint(2, "\thisaction=%s => %s\n", actstr(hisaction), actstr(hisaction));
2309a747e4fSDavid du Colombier 		return hisaction;
2317dd7cddfSDavid du Colombier 	}
2327dd7cddfSDavid du Colombier 
2339a747e4fSDavid du Colombier 	/* convert to lower case */
2349a747e4fSDavid du Colombier 	lpath = s_copy(s_to_c(path));
2359a747e4fSDavid du Colombier 	s_tolower(lpath);
2367dd7cddfSDavid du Colombier 
2379a747e4fSDavid du Colombier 	/* classify */
2389a747e4fSDavid du Colombier 	action = getaction(s_to_c(lpath), "account");
2399a747e4fSDavid du Colombier 	if(debug)
2409a747e4fSDavid du Colombier 		fprint(2, "\tgetaction account %s => %s\n", s_to_c(lpath), actstr(action));
2417dd7cddfSDavid du Colombier 	s_free(lpath);
2427dd7cddfSDavid du Colombier 	return action;
2437dd7cddfSDavid du Colombier }
2447dd7cddfSDavid du Colombier 
2457dd7cddfSDavid du Colombier /*
2467dd7cddfSDavid du Colombier  * get a canonicalized line: a string of null-terminated lower-case
2477dd7cddfSDavid du Colombier  * tokens with a two null bytes at the end.
2487dd7cddfSDavid du Colombier  */
2497dd7cddfSDavid du Colombier static char*
getline(Biobuf * bp)2507dd7cddfSDavid du Colombier getline(Biobuf *bp)
2517dd7cddfSDavid du Colombier {
2527dd7cddfSDavid du Colombier 	char c, *cp, *p, *q;
2537dd7cddfSDavid du Colombier 	int n;
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	static char *buf;
2567dd7cddfSDavid du Colombier 	static int bufsize;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	for(;;){
2597dd7cddfSDavid du Colombier 		cp = Brdline(bp, '\n');
2607dd7cddfSDavid du Colombier 		if(cp == 0)
2617dd7cddfSDavid du Colombier 			return 0;
2627dd7cddfSDavid du Colombier 		n = Blinelen(bp);
2637dd7cddfSDavid du Colombier 		cp[n-1] = 0;
2647dd7cddfSDavid du Colombier 		if(buf == 0 || bufsize < n+1){
2657dd7cddfSDavid du Colombier 			bufsize += 512;
2667dd7cddfSDavid du Colombier 			if(bufsize < n+1)
2677dd7cddfSDavid du Colombier 				bufsize = n+1;
2687dd7cddfSDavid du Colombier 			buf = realloc(buf, bufsize);
2697dd7cddfSDavid du Colombier 			if(buf == 0)
2707dd7cddfSDavid du Colombier 				break;
2717dd7cddfSDavid du Colombier 		}
2727dd7cddfSDavid du Colombier 		q = buf;
2737dd7cddfSDavid du Colombier 		for (p = cp; *p; p++){
2747dd7cddfSDavid du Colombier 			c = *p;
2757dd7cddfSDavid du Colombier 			if(c == '\\' && p[1])	/* we don't allow \<newline> */
2767dd7cddfSDavid du Colombier 				c = *++p;
2777dd7cddfSDavid du Colombier 			else
2787dd7cddfSDavid du Colombier 			if(c == '#')
2797dd7cddfSDavid du Colombier 				break;
2807dd7cddfSDavid du Colombier 			else
2817dd7cddfSDavid du Colombier 			if(c == ' ' || c == '\t' || c == ',')
2827dd7cddfSDavid du Colombier 				if(q == buf || q[-1] == 0)
2837dd7cddfSDavid du Colombier 					continue;
2847dd7cddfSDavid du Colombier 				else
2857dd7cddfSDavid du Colombier 					c = 0;
2867dd7cddfSDavid du Colombier 			*q++ = tolower(c);
2877dd7cddfSDavid du Colombier 		}
2887dd7cddfSDavid du Colombier 		if(q != buf){
2897dd7cddfSDavid du Colombier 			if(q[-1])
2907dd7cddfSDavid du Colombier 				*q++ = 0;
2917dd7cddfSDavid du Colombier 			*q = 0;
2927dd7cddfSDavid du Colombier 			break;
2937dd7cddfSDavid du Colombier 		}
2947dd7cddfSDavid du Colombier 	}
2957dd7cddfSDavid du Colombier 	return buf;
2967dd7cddfSDavid du Colombier }
2977dd7cddfSDavid du Colombier 
2986b6b9ac8SDavid du Colombier static int
isourdom(char * s)2996b6b9ac8SDavid du Colombier isourdom(char *s)
3006b6b9ac8SDavid du Colombier {
3016b6b9ac8SDavid du Colombier 	Link *l;
3026b6b9ac8SDavid du Colombier 
3036b6b9ac8SDavid du Colombier 	if(strchr(s, '.') == nil)
3046b6b9ac8SDavid du Colombier 		return 1;
3056b6b9ac8SDavid du Colombier 
3066b6b9ac8SDavid du Colombier 	for(l = ourdoms.first; l; l = l->next){
3076b6b9ac8SDavid du Colombier 		if(dommatch(s, s_to_c(l->p)) == 0)
3086b6b9ac8SDavid du Colombier 			return 1;
3096b6b9ac8SDavid du Colombier 	}
3106b6b9ac8SDavid du Colombier 	return 0;
3116b6b9ac8SDavid du Colombier }
3126b6b9ac8SDavid du Colombier 
3137dd7cddfSDavid du Colombier int
forwarding(String * path)3147dd7cddfSDavid du Colombier forwarding(String *path)
3157dd7cddfSDavid du Colombier {
3167dd7cddfSDavid du Colombier 	char *cp, *s;
3177dd7cddfSDavid du Colombier 	String *lpath;
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	if(debug)
3207dd7cddfSDavid du Colombier 		fprint(2, "forwarding(%s)\n", s_to_c(path));
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier 	/* first check if they want loopback */
3237dd7cddfSDavid du Colombier 	lpath = s_copy(s_to_c(s_restart(path)));
3249a747e4fSDavid du Colombier 	if(nci->rsys && *nci->rsys){
3257dd7cddfSDavid du Colombier 		cp = s_to_c(lpath);
3267dd7cddfSDavid du Colombier 		if(strncmp(cp, "[]!", 3) == 0){
3277dd7cddfSDavid du Colombier found:
3287dd7cddfSDavid du Colombier 			s_append(path, "[");
3299a747e4fSDavid du Colombier 			s_append(path, nci->rsys);
3307dd7cddfSDavid du Colombier 			s_append(path, "]!");
3317dd7cddfSDavid du Colombier 			s_append(path, cp+3);
3327dd7cddfSDavid du Colombier 			s_terminate(path);
3337dd7cddfSDavid du Colombier 			s_free(lpath);
3347dd7cddfSDavid du Colombier 			return 0;
3357dd7cddfSDavid du Colombier 		}
3367dd7cddfSDavid du Colombier 		cp = strchr(cp,'!');			/* skip our domain and check next */
3377dd7cddfSDavid du Colombier 		if(cp++ && strncmp(cp, "[]!", 3) == 0)
3387dd7cddfSDavid du Colombier 			goto found;
3397dd7cddfSDavid du Colombier 	}
3409a747e4fSDavid du Colombier 
3419a747e4fSDavid du Colombier 	/* if mail is from a trusted IP addr, allow it to forward */
3427dd7cddfSDavid du Colombier 	if(trusted) {
3437dd7cddfSDavid du Colombier 		s_free(lpath);
3447dd7cddfSDavid du Colombier 		return 0;
3457dd7cddfSDavid du Colombier 	}
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier 	/* sender is untrusted; ensure receiver is in one of our domains */
3487dd7cddfSDavid du Colombier 	for(cp = s_to_c(lpath); *cp; cp++)		/* convert receiver lc */
3497dd7cddfSDavid du Colombier 		*cp = tolower(*cp);
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier 	for(s = s_to_c(lpath); cp = strchr(s, '!'); s = cp+1){
3527dd7cddfSDavid du Colombier 		*cp = 0;
3536b6b9ac8SDavid du Colombier 		if(!isourdom(s)){
3547dd7cddfSDavid du Colombier 			s_free(lpath);
3557dd7cddfSDavid du Colombier 			return 1;
3567dd7cddfSDavid du Colombier 		}
3577dd7cddfSDavid du Colombier 	}
3587dd7cddfSDavid du Colombier 	s_free(lpath);
3597dd7cddfSDavid du Colombier 	return 0;
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier int
masquerade(String * path,char * him)3636b6b9ac8SDavid du Colombier masquerade(String *path, char *him)
3646b6b9ac8SDavid du Colombier {
3656b6b9ac8SDavid du Colombier 	char *cp, *s;
3666b6b9ac8SDavid du Colombier 	String *lpath;
3676b6b9ac8SDavid du Colombier 	int rv = 0;
3686b6b9ac8SDavid du Colombier 
3696b6b9ac8SDavid du Colombier 	if(debug)
370*c6569576SDavid du Colombier 		fprint(2, "masquerade(%s) ", s_to_c(path));
3716b6b9ac8SDavid du Colombier 
372*c6569576SDavid du Colombier 	if(trusted || path == nil) {
373*c6569576SDavid du Colombier 		if(debug)
374*c6569576SDavid du Colombier 			fprint(2, "0\n");
3756b6b9ac8SDavid du Colombier 		return 0;
376*c6569576SDavid du Colombier 	}
3776b6b9ac8SDavid du Colombier 
3786b6b9ac8SDavid du Colombier 	lpath = s_copy(s_to_c(path));
3796b6b9ac8SDavid du Colombier 
3806b6b9ac8SDavid du Colombier 	/* sender is untrusted; ensure receiver is in one of our domains */
3816b6b9ac8SDavid du Colombier 	for(cp = s_to_c(lpath); *cp; cp++)		/* convert receiver lc */
3826b6b9ac8SDavid du Colombier 		*cp = tolower(*cp);
383dc5a79c1SDavid du Colombier 	s = s_to_c(lpath);
3846b6b9ac8SDavid du Colombier 
3856b6b9ac8SDavid du Colombier 	/* scan first element of ! or last element of @ paths */
3866b6b9ac8SDavid du Colombier 	if((cp = strchr(s, '!')) != nil){
3876b6b9ac8SDavid du Colombier 		*cp = 0;
3886b6b9ac8SDavid du Colombier 		if(isourdom(s))
3896b6b9ac8SDavid du Colombier 			rv = 1;
3906b6b9ac8SDavid du Colombier 	} else if((cp = strrchr(s, '@')) != nil){
3916b6b9ac8SDavid du Colombier 		if(isourdom(cp+1))
3926b6b9ac8SDavid du Colombier 			rv = 1;
3936b6b9ac8SDavid du Colombier 	} else {
3946b6b9ac8SDavid du Colombier 		if(isourdom(him))
3956b6b9ac8SDavid du Colombier 			rv = 1;
3966b6b9ac8SDavid du Colombier 	}
3976b6b9ac8SDavid du Colombier 
3986b6b9ac8SDavid du Colombier 	s_free(lpath);
399*c6569576SDavid du Colombier 	if (debug)
400*c6569576SDavid du Colombier 		fprint(2, "%d\n", rv);
4016b6b9ac8SDavid du Colombier 	return rv;
4026b6b9ac8SDavid du Colombier }
4036b6b9ac8SDavid du Colombier 
404e288d156SDavid du Colombier /* this is a v4 only check */
405e288d156SDavid du Colombier static int
cidrcheck(char * cp)4067dd7cddfSDavid du Colombier cidrcheck(char *cp)
4077dd7cddfSDavid du Colombier {
4087dd7cddfSDavid du Colombier 	char *p;
4097dd7cddfSDavid du Colombier 	ulong a, m;
4107dd7cddfSDavid du Colombier 	uchar addr[IPv4addrlen];
4117dd7cddfSDavid du Colombier 	uchar mask[IPv4addrlen];
4127dd7cddfSDavid du Colombier 
413e288d156SDavid du Colombier 	if(v4peerip == 0)
4147dd7cddfSDavid du Colombier 		return 0;
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier 	/* parse a list of CIDR addresses comparing each to the peer IP addr */
4177dd7cddfSDavid du Colombier 	while(cp && *cp){
4187dd7cddfSDavid du Colombier 		v4parsecidr(addr, mask, cp);
4197dd7cddfSDavid du Colombier 		a = nhgetl(addr);
4207dd7cddfSDavid du Colombier 		m = nhgetl(mask);
4217dd7cddfSDavid du Colombier 		/*
4227dd7cddfSDavid du Colombier 		 * if a mask isn't specified, we build a minimal mask
4237dd7cddfSDavid du Colombier 		 * instead of using the default mask for that net.  in this
4247dd7cddfSDavid du Colombier 		 * case we never allow a class A mask (0xff000000).
4257dd7cddfSDavid du Colombier 		 */
4267dd7cddfSDavid du Colombier 		if(strchr(cp, '/') == 0){
4277dd7cddfSDavid du Colombier 			m = 0xff000000;
4287dd7cddfSDavid du Colombier 			p = cp;
4297dd7cddfSDavid du Colombier 			for(p = strchr(p, '.'); p && p[1]; p = strchr(p+1, '.'))
4307dd7cddfSDavid du Colombier 					m = (m>>8)|0xff000000;
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier 			/* force at least a class B */
4337dd7cddfSDavid du Colombier 			m |= 0xffff0000;
4347dd7cddfSDavid du Colombier 		}
435e288d156SDavid du Colombier 		if((v4peerip&m) == a)
4367dd7cddfSDavid du Colombier 			return 1;
4377dd7cddfSDavid du Colombier 		cp += strlen(cp)+1;
4387dd7cddfSDavid du Colombier 	}
4397dd7cddfSDavid du Colombier 	return 0;
4407dd7cddfSDavid du Colombier }
4417dd7cddfSDavid du Colombier 
442e288d156SDavid du Colombier int
isbadguy(void)443e288d156SDavid du Colombier isbadguy(void)
444e288d156SDavid du Colombier {
445e288d156SDavid du Colombier 	Link *l;
446e288d156SDavid du Colombier 
447e288d156SDavid du Colombier 	/* check if this IP address is banned */
448e288d156SDavid du Colombier 	for(l = badguys.first; l; l = l->next)
449e288d156SDavid du Colombier 		if(cidrcheck(s_to_c(l->p)))
450e288d156SDavid du Colombier 			return 1;
451e288d156SDavid du Colombier 
452e288d156SDavid du Colombier 	return 0;
453e288d156SDavid du Colombier }
454e288d156SDavid du Colombier 
455e288d156SDavid du Colombier void
addbadguy(char * p)456e288d156SDavid du Colombier addbadguy(char *p)
457e288d156SDavid du Colombier {
458e288d156SDavid du Colombier 	listadd(&badguys, s_copy(p));
459e288d156SDavid du Colombier };
460e288d156SDavid du Colombier 
4617dd7cddfSDavid du Colombier char*
dumpfile(char * sender)4627dd7cddfSDavid du Colombier dumpfile(char *sender)
4637dd7cddfSDavid du Colombier {
4647dd7cddfSDavid du Colombier 	int i, fd;
4657dd7cddfSDavid du Colombier 	ulong h;
4667dd7cddfSDavid du Colombier 	static char buf[512];
4677dd7cddfSDavid du Colombier 	char *cp;
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier 	if (sflag == 1){
4707dd7cddfSDavid du Colombier 		cp = ctime(time(0));
4717dd7cddfSDavid du Colombier 		cp[7] = 0;
4727dd7cddfSDavid du Colombier 		if(cp[8] == ' ')
4737dd7cddfSDavid du Colombier 			sprint(buf, "%s/queue.dump/%s%c", SPOOL, cp+4, cp[9]);
4747dd7cddfSDavid du Colombier 		else
4757dd7cddfSDavid du Colombier 			sprint(buf, "%s/queue.dump/%s%c%c", SPOOL, cp+4, cp[8], cp[9]);
4767dd7cddfSDavid du Colombier 		cp = buf+strlen(buf);
4777dd7cddfSDavid du Colombier 		if(access(buf, 0) < 0 && sysmkdir(buf, 0777) < 0)
4787dd7cddfSDavid du Colombier 			return "/dev/null";
4797dd7cddfSDavid du Colombier 		h = 0;
4807dd7cddfSDavid du Colombier 		while(*sender)
4817dd7cddfSDavid du Colombier 			h = h*257 + *sender++;
4827dd7cddfSDavid du Colombier 		for(i = 0; i < 50; i++){
4837dd7cddfSDavid du Colombier 			h += lrand();
4847dd7cddfSDavid du Colombier 			sprint(cp, "/%lud", h);
4857dd7cddfSDavid du Colombier 			if(access(buf, 0) >= 0)
4867dd7cddfSDavid du Colombier 				continue;
48759cc4ca5SDavid du Colombier 			fd = syscreate(buf, ORDWR, 0666);
4887dd7cddfSDavid du Colombier 			if(fd >= 0){
4897dd7cddfSDavid du Colombier 				if(debug)
4907dd7cddfSDavid du Colombier 					fprint(2, "saving in %s\n", buf);
4917dd7cddfSDavid du Colombier 				close(fd);
4927dd7cddfSDavid du Colombier 				return buf;
4937dd7cddfSDavid du Colombier 			}
4947dd7cddfSDavid du Colombier 		}
4957dd7cddfSDavid du Colombier 	}
4967dd7cddfSDavid du Colombier 	return "/dev/null";
4977dd7cddfSDavid du Colombier }
49880ee5cbfSDavid du Colombier 
4992b7fd5adSDavid du Colombier char *validator = "/mail/lib/validateaddress";
5002b7fd5adSDavid du Colombier 
50180ee5cbfSDavid du Colombier int
recipok(char * user)50280ee5cbfSDavid du Colombier recipok(char *user)
50380ee5cbfSDavid du Colombier {
50480ee5cbfSDavid du Colombier 	char *cp, *p, c;
50580ee5cbfSDavid du Colombier 	char buf[512];
50680ee5cbfSDavid du Colombier 	int n;
50780ee5cbfSDavid du Colombier 	Biobuf *bp;
5082b7fd5adSDavid du Colombier 	int pid;
5092b7fd5adSDavid du Colombier 	Waitmsg *w;
5102b7fd5adSDavid du Colombier 
5112b7fd5adSDavid du Colombier 	if(shellchars(user)){
5122b7fd5adSDavid du Colombier 		syslog(0, "smtpd", "shellchars in user name");
5132b7fd5adSDavid du Colombier 		return 0;
5142b7fd5adSDavid du Colombier 	}
5152b7fd5adSDavid du Colombier 
5162b7fd5adSDavid du Colombier 	if(access(validator, AEXEC) == 0)
5172b7fd5adSDavid du Colombier 	switch(pid = fork()) {
5182b7fd5adSDavid du Colombier 	case -1:
5192b7fd5adSDavid du Colombier 		break;
5202b7fd5adSDavid du Colombier 	case 0:
5212b7fd5adSDavid du Colombier 		execl(validator, "validateaddress", user, nil);
5222b7fd5adSDavid du Colombier 		exits(0);
5232b7fd5adSDavid du Colombier 	default:
5242b7fd5adSDavid du Colombier 		while(w = wait()) {
5252b7fd5adSDavid du Colombier 			if(w->pid != pid)
5262b7fd5adSDavid du Colombier 				continue;
5272b7fd5adSDavid du Colombier 			if(w->msg[0] != 0){
5282b7fd5adSDavid du Colombier 				/*
5292b7fd5adSDavid du Colombier 				syslog(0, "smtpd", "validateaddress %s: %s", user, w->msg);
5302b7fd5adSDavid du Colombier 				*/
5312b7fd5adSDavid du Colombier 				return 0;
5322b7fd5adSDavid du Colombier 			}
5332b7fd5adSDavid du Colombier 			break;
5342b7fd5adSDavid du Colombier 		}
5352b7fd5adSDavid du Colombier 	}
53680ee5cbfSDavid du Colombier 
53780ee5cbfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s/names.blocked", UPASLIB);
53880ee5cbfSDavid du Colombier 	bp = sysopen(buf, "r", 0);
53980ee5cbfSDavid du Colombier 	if(bp == 0)
54080ee5cbfSDavid du Colombier 		return 1;
54180ee5cbfSDavid du Colombier 	for(;;){
54280ee5cbfSDavid du Colombier 		cp = Brdline(bp, '\n');
54380ee5cbfSDavid du Colombier 		if(cp == 0)
54480ee5cbfSDavid du Colombier 			break;
54580ee5cbfSDavid du Colombier 		n = Blinelen(bp);
54680ee5cbfSDavid du Colombier 		cp[n-1] = 0;
54780ee5cbfSDavid du Colombier 
54880ee5cbfSDavid du Colombier 		while(*cp == ' ' || *cp == '\t')
54980ee5cbfSDavid du Colombier 			cp++;
55080ee5cbfSDavid du Colombier 		for(p = cp; c = *p; p++){
55180ee5cbfSDavid du Colombier 			if(c == '#')
55280ee5cbfSDavid du Colombier 				break;
55380ee5cbfSDavid du Colombier 			if(c == ' ' || c == '\t')
55480ee5cbfSDavid du Colombier 				break;
55580ee5cbfSDavid du Colombier 		}
55680ee5cbfSDavid du Colombier 		if(p > cp){
55780ee5cbfSDavid du Colombier 			*p = 0;
55880ee5cbfSDavid du Colombier 			if(cistrcmp(user, cp) == 0){
5592b7fd5adSDavid du Colombier 				syslog(0, "smtpd", "names.blocked blocks %s", user);
56080ee5cbfSDavid du Colombier 				Bterm(bp);
56180ee5cbfSDavid du Colombier 				return 0;
56280ee5cbfSDavid du Colombier 			}
56380ee5cbfSDavid du Colombier 		}
56480ee5cbfSDavid du Colombier 	}
56580ee5cbfSDavid du Colombier 	Bterm(bp);
56680ee5cbfSDavid du Colombier 	return 1;
567d9306527SDavid du Colombier }
568d9306527SDavid du Colombier 
569d9306527SDavid du Colombier /*
570d9306527SDavid du Colombier  *  a user can opt out of spam filtering by creating
571d9306527SDavid du Colombier  *  a file in his mail directory named 'nospamfiltering'.
572d9306527SDavid du Colombier  */
573d9306527SDavid du Colombier int
optoutofspamfilter(char * addr)574d9306527SDavid du Colombier optoutofspamfilter(char *addr)
575d9306527SDavid du Colombier {
576d9306527SDavid du Colombier 	char *p, *f;
577d9306527SDavid du Colombier 	int rv;
578d9306527SDavid du Colombier 
579d9306527SDavid du Colombier 	p = strchr(addr, '!');
580d9306527SDavid du Colombier 	if(p)
581d9306527SDavid du Colombier 		p++;
582d9306527SDavid du Colombier 	else
583d9306527SDavid du Colombier 		p = addr;
584d9306527SDavid du Colombier 
585d9306527SDavid du Colombier 
586d9306527SDavid du Colombier 	rv = 0;
587d9306527SDavid du Colombier 	f = smprint("/mail/box/%s/nospamfiltering", p);
588d9306527SDavid du Colombier 	if(f != nil){
589d9306527SDavid du Colombier 		rv = access(f, 0)==0;
590d9306527SDavid du Colombier 		free(f);
591d9306527SDavid du Colombier 	}
592d9306527SDavid du Colombier 
593d9306527SDavid du Colombier 	return rv;
59480ee5cbfSDavid du Colombier }
595