xref: /plan9/sys/src/cmd/upas/smtp/spam.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
17dd7cddfSDavid du Colombier #include "common.h"
27dd7cddfSDavid du Colombier #include "smtpd.h"
37dd7cddfSDavid 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;
459a747e4fSDavid du Colombier 
467dd7cddfSDavid du Colombier static	char*	getline(Biobuf*);
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier static int
497dd7cddfSDavid du Colombier findkey(char *val, Keyword *p)
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier 	for(; p->name; p++)
537dd7cddfSDavid du Colombier 		if(strcmp(val, p->name) == 0)
547dd7cddfSDavid du Colombier 				break;
557dd7cddfSDavid du Colombier 	return p->code;
567dd7cddfSDavid du Colombier }
577dd7cddfSDavid du Colombier 
589a747e4fSDavid du Colombier char*
599a747e4fSDavid du Colombier actstr(int a)
609a747e4fSDavid du Colombier {
619a747e4fSDavid du Colombier 	char buf[32];
629a747e4fSDavid du Colombier 	Keyword *p;
639a747e4fSDavid du Colombier 
649a747e4fSDavid du Colombier 	for(p=actions; p->name; p++)
659a747e4fSDavid du Colombier 		if(p->code == a)
669a747e4fSDavid du Colombier 			return p->name;
679a747e4fSDavid du Colombier 	if(a==NONE)
689a747e4fSDavid du Colombier 		return "none";
699a747e4fSDavid du Colombier 	sprint(buf, "%d", a);
709a747e4fSDavid du Colombier 	return buf;
719a747e4fSDavid du Colombier }
729a747e4fSDavid du Colombier 
739a747e4fSDavid du Colombier int
749a747e4fSDavid du Colombier getaction(char *s, char *type)
759a747e4fSDavid du Colombier {
769a747e4fSDavid du Colombier 	char buf[1024];
779a747e4fSDavid du Colombier 	Keyword *k;
789a747e4fSDavid du Colombier 
799a747e4fSDavid du Colombier 	if(s == nil || *s == 0)
809a747e4fSDavid du Colombier 		return ACCEPT;
819a747e4fSDavid du Colombier 
829a747e4fSDavid du Colombier 	for(k = actions; k->name != 0; k++){
839a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "/mail/ratify/%s/%s/%s", k->name, type, s);
849a747e4fSDavid du Colombier 		if(access(buf,0) >= 0)
859a747e4fSDavid du Colombier 			return k->code;
869a747e4fSDavid du Colombier 	}
879a747e4fSDavid du Colombier 	return ACCEPT;
889a747e4fSDavid du Colombier }
899a747e4fSDavid du Colombier 
909a747e4fSDavid du Colombier int
919a747e4fSDavid du Colombier istrusted(char *s)
929a747e4fSDavid du Colombier {
939a747e4fSDavid du Colombier 	char buf[1024];
949a747e4fSDavid du Colombier 
959a747e4fSDavid du Colombier 	if(s == nil || *s == 0)
969a747e4fSDavid du Colombier 		return 0;
979a747e4fSDavid du Colombier 
989a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "/mail/ratify/trusted/%s", s);
999a747e4fSDavid du Colombier 	return access(buf,0) >= 0;
1009a747e4fSDavid du Colombier }
1019a747e4fSDavid du Colombier 
1027dd7cddfSDavid du Colombier void
1037dd7cddfSDavid du Colombier getconf(void)
1047dd7cddfSDavid du Colombier {
1057dd7cddfSDavid du Colombier 	Biobuf *bp;
1067dd7cddfSDavid du Colombier 	char *cp, *p;
1077dd7cddfSDavid du Colombier 	String *s;
1087dd7cddfSDavid du Colombier 	char buf[512];
1099a747e4fSDavid du Colombier 
1109a747e4fSDavid du Colombier 	trusted = istrusted(nci->rsys);
1119a747e4fSDavid du Colombier 	hisaction = getaction(nci->rsys, "ip");
1129a747e4fSDavid du Colombier 	if(debug){
1139a747e4fSDavid du Colombier 		fprint(2, "istrusted(%s)=%d\n", nci->rsys, trusted);
1149a747e4fSDavid du Colombier 		fprint(2, "getaction(%s, ip)=%s\n", nci->rsys, actstr(hisaction));
11580ee5cbfSDavid du Colombier 	}
1167dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s/smtpd.conf", UPASLIB);
1177dd7cddfSDavid du Colombier 	bp = sysopen(buf, "r", 0);
1187dd7cddfSDavid du Colombier 	if(bp == 0)
1197dd7cddfSDavid du Colombier 		return;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	for(;;){
1227dd7cddfSDavid du Colombier 		cp = getline(bp);
1237dd7cddfSDavid du Colombier 		if(cp == 0)
1247dd7cddfSDavid du Colombier 			break;
1257dd7cddfSDavid du Colombier 		p = cp+strlen(cp)+1;
1267dd7cddfSDavid du Colombier 		switch(findkey(cp, options)){
1277dd7cddfSDavid du Colombier 		case NORELAY:
1287dd7cddfSDavid du Colombier 			if(fflag == 0 && strcmp(p, "on") == 0)
1297dd7cddfSDavid du Colombier 				fflag++;
1307dd7cddfSDavid du Colombier 			break;
1317dd7cddfSDavid du Colombier 		case DNSVERIFY:
1327dd7cddfSDavid du Colombier 			if(rflag == 0 && strcmp(p, "on") == 0)
1337dd7cddfSDavid du Colombier 				rflag++;
1347dd7cddfSDavid du Colombier 			break;
1357dd7cddfSDavid du Colombier 		case SAVEBLOCK:
1367dd7cddfSDavid du Colombier 			if(sflag == 0 && strcmp(p, "on") == 0)
1377dd7cddfSDavid du Colombier 				sflag++;
1387dd7cddfSDavid du Colombier 			break;
1397dd7cddfSDavid du Colombier 		case DOMNAME:
1407dd7cddfSDavid du Colombier 			if(dom == 0)
1417dd7cddfSDavid du Colombier 				dom = strdup(p);
1427dd7cddfSDavid du Colombier 			break;
1437dd7cddfSDavid du Colombier 		case OURNETS:
1447dd7cddfSDavid du Colombier 			if (trusted == 0)
1457dd7cddfSDavid du Colombier 				trusted = cidrcheck(p);
1467dd7cddfSDavid du Colombier 			break;
1477dd7cddfSDavid du Colombier 		case OURDOMS:
1487dd7cddfSDavid du Colombier 			while(*p){
1497dd7cddfSDavid du Colombier 				s = s_new();
1507dd7cddfSDavid du Colombier 				s_append(s, p);
1517dd7cddfSDavid du Colombier 				listadd(&ourdoms, s);
1527dd7cddfSDavid du Colombier 				p += strlen(p)+1;
1537dd7cddfSDavid du Colombier 			}
1547dd7cddfSDavid du Colombier 			break;
1557dd7cddfSDavid du Colombier 		default:
1567dd7cddfSDavid du Colombier 			break;
1577dd7cddfSDavid du Colombier 		}
1587dd7cddfSDavid du Colombier 	}
1597dd7cddfSDavid du Colombier 	sysclose(bp);
1607dd7cddfSDavid du Colombier }
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier /*
1637dd7cddfSDavid du Colombier  *	match a user name.  the only meta-char is '*' which matches all
1647dd7cddfSDavid du Colombier  *	characters.  we only allow it as "*", which matches anything or
1657dd7cddfSDavid du Colombier  *	an * at the end of the name (e.g., "username*") which matches
1667dd7cddfSDavid du Colombier  *	trailing characters.
1677dd7cddfSDavid du Colombier  */
1687dd7cddfSDavid du Colombier static int
1697dd7cddfSDavid du Colombier usermatch(char *pathuser, char *specuser)
1707dd7cddfSDavid du Colombier {
1717dd7cddfSDavid du Colombier 	int n;
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	n = strlen(specuser)-1;
1747dd7cddfSDavid du Colombier 	if(specuser[n] == '*'){
1757dd7cddfSDavid du Colombier 		if(n == 0)		/* match everything */
1767dd7cddfSDavid du Colombier 			return 0;
1777dd7cddfSDavid du Colombier 		return strncmp(pathuser, specuser, n);
1787dd7cddfSDavid du Colombier 	}
1797dd7cddfSDavid du Colombier 	return strcmp(pathuser, specuser);
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier static int
1837dd7cddfSDavid du Colombier dommatch(char *pathdom, char *specdom)
1847dd7cddfSDavid du Colombier {
1857dd7cddfSDavid du Colombier 	int n;
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier 	if (*specdom == '*'){
1887dd7cddfSDavid du Colombier 		if (specdom[1] == '.' && specdom[2]){
1897dd7cddfSDavid du Colombier 			specdom += 2;
1907dd7cddfSDavid du Colombier 			n = strlen(pathdom)-strlen(specdom);
1917dd7cddfSDavid du Colombier 			if(n == 0 || (n > 0 && pathdom[n-1] == '.'))
1927dd7cddfSDavid du Colombier 				return strcmp(pathdom+n, specdom);
1937dd7cddfSDavid du Colombier 			return n;
1947dd7cddfSDavid du Colombier 		}
1957dd7cddfSDavid du Colombier 	}
1967dd7cddfSDavid du Colombier 	return strcmp(pathdom, specdom);
1977dd7cddfSDavid du Colombier }
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier /*
2009a747e4fSDavid du Colombier  *  figure out action for this sender
2017dd7cddfSDavid du Colombier  */
2027dd7cddfSDavid du Colombier int
2037dd7cddfSDavid du Colombier blocked(String *path)
2047dd7cddfSDavid du Colombier {
2059a747e4fSDavid du Colombier 	String *lpath;
2069a747e4fSDavid du Colombier 	int action;
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	if(debug)
2097dd7cddfSDavid du Colombier 		fprint(2, "blocked(%s)\n", s_to_c(path));
2107dd7cddfSDavid du Colombier 
2119a747e4fSDavid du Colombier 	/* if the sender's IP address is blessed, ignore sender email address */
2129a747e4fSDavid du Colombier 	if(trusted){
2139a747e4fSDavid du Colombier 		if(debug)
2149a747e4fSDavid du Colombier 			fprint(2, "\ttrusted => trusted\n");
2159a747e4fSDavid du Colombier 		return TRUSTED;
2167dd7cddfSDavid du Colombier 	}
2177dd7cddfSDavid du Colombier 
2189a747e4fSDavid du Colombier 	/* if sender's IP address is blocked, ignore sender email address */
2199a747e4fSDavid du Colombier 	if(hisaction != ACCEPT){
2209a747e4fSDavid du Colombier 		if(debug)
2219a747e4fSDavid du Colombier 			fprint(2, "\thisaction=%s => %s\n", actstr(hisaction), actstr(hisaction));
2229a747e4fSDavid du Colombier 		return hisaction;
2237dd7cddfSDavid du Colombier 	}
2247dd7cddfSDavid du Colombier 
2259a747e4fSDavid du Colombier 	/* convert to lower case */
2269a747e4fSDavid du Colombier 	lpath = s_copy(s_to_c(path));
2279a747e4fSDavid du Colombier 	s_tolower(lpath);
2287dd7cddfSDavid du Colombier 
2299a747e4fSDavid du Colombier 	/* classify */
2309a747e4fSDavid du Colombier 	action = getaction(s_to_c(lpath), "account");
2319a747e4fSDavid du Colombier 	if(debug)
2329a747e4fSDavid du Colombier 		fprint(2, "\tgetaction account %s => %s\n", s_to_c(lpath), actstr(action));
2337dd7cddfSDavid du Colombier 	s_free(lpath);
2347dd7cddfSDavid du Colombier 	return action;
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier /*
2387dd7cddfSDavid du Colombier  * get a canonicalized line: a string of null-terminated lower-case
2397dd7cddfSDavid du Colombier  * tokens with a two null bytes at the end.
2407dd7cddfSDavid du Colombier  */
2417dd7cddfSDavid du Colombier static char*
2427dd7cddfSDavid du Colombier getline(Biobuf *bp)
2437dd7cddfSDavid du Colombier {
2447dd7cddfSDavid du Colombier 	char c, *cp, *p, *q;
2457dd7cddfSDavid du Colombier 	int n;
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier 	static char *buf;
2487dd7cddfSDavid du Colombier 	static int bufsize;
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier 	for(;;){
2517dd7cddfSDavid du Colombier 		cp = Brdline(bp, '\n');
2527dd7cddfSDavid du Colombier 		if(cp == 0)
2537dd7cddfSDavid du Colombier 			return 0;
2547dd7cddfSDavid du Colombier 		n = Blinelen(bp);
2557dd7cddfSDavid du Colombier 		cp[n-1] = 0;
2567dd7cddfSDavid du Colombier 		if(buf == 0 || bufsize < n+1){
2577dd7cddfSDavid du Colombier 			bufsize += 512;
2587dd7cddfSDavid du Colombier 			if(bufsize < n+1)
2597dd7cddfSDavid du Colombier 				bufsize = n+1;
2607dd7cddfSDavid du Colombier 			buf = realloc(buf, bufsize);
2617dd7cddfSDavid du Colombier 			if(buf == 0)
2627dd7cddfSDavid du Colombier 				break;
2637dd7cddfSDavid du Colombier 		}
2647dd7cddfSDavid du Colombier 		q = buf;
2657dd7cddfSDavid du Colombier 		for (p = cp; *p; p++){
2667dd7cddfSDavid du Colombier 			c = *p;
2677dd7cddfSDavid du Colombier 			if(c == '\\' && p[1])	/* we don't allow \<newline> */
2687dd7cddfSDavid du Colombier 				c = *++p;
2697dd7cddfSDavid du Colombier 			else
2707dd7cddfSDavid du Colombier 			if(c == '#')
2717dd7cddfSDavid du Colombier 				break;
2727dd7cddfSDavid du Colombier 			else
2737dd7cddfSDavid du Colombier 			if(c == ' ' || c == '\t' || c == ',')
2747dd7cddfSDavid du Colombier 				if(q == buf || q[-1] == 0)
2757dd7cddfSDavid du Colombier 					continue;
2767dd7cddfSDavid du Colombier 				else
2777dd7cddfSDavid du Colombier 					c = 0;
2787dd7cddfSDavid du Colombier 			*q++ = tolower(c);
2797dd7cddfSDavid du Colombier 		}
2807dd7cddfSDavid du Colombier 		if(q != buf){
2817dd7cddfSDavid du Colombier 			if(q[-1])
2827dd7cddfSDavid du Colombier 				*q++ = 0;
2837dd7cddfSDavid du Colombier 			*q = 0;
2847dd7cddfSDavid du Colombier 			break;
2857dd7cddfSDavid du Colombier 		}
2867dd7cddfSDavid du Colombier 	}
2877dd7cddfSDavid du Colombier 	return buf;
2887dd7cddfSDavid du Colombier }
2897dd7cddfSDavid du Colombier 
290*6b6b9ac8SDavid du Colombier static int
291*6b6b9ac8SDavid du Colombier isourdom(char *s)
292*6b6b9ac8SDavid du Colombier {
293*6b6b9ac8SDavid du Colombier 	Link *l;
294*6b6b9ac8SDavid du Colombier 
295*6b6b9ac8SDavid du Colombier 	if(strchr(s, '.') == nil)
296*6b6b9ac8SDavid du Colombier 		return 1;
297*6b6b9ac8SDavid du Colombier 
298*6b6b9ac8SDavid du Colombier 	for(l = ourdoms.first; l; l = l->next){
299*6b6b9ac8SDavid du Colombier 		if(dommatch(s, s_to_c(l->p)) == 0)
300*6b6b9ac8SDavid du Colombier 			return 1;
301*6b6b9ac8SDavid du Colombier 	}
302*6b6b9ac8SDavid du Colombier 	return 0;
303*6b6b9ac8SDavid du Colombier }
304*6b6b9ac8SDavid du Colombier 
3057dd7cddfSDavid du Colombier int
3067dd7cddfSDavid du Colombier forwarding(String *path)
3077dd7cddfSDavid du Colombier {
3087dd7cddfSDavid du Colombier 	char *cp, *s;
3097dd7cddfSDavid du Colombier 	String *lpath;
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier 	if(debug)
3127dd7cddfSDavid du Colombier 		fprint(2, "forwarding(%s)\n", s_to_c(path));
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 	/* first check if they want loopback */
3157dd7cddfSDavid du Colombier 	lpath = s_copy(s_to_c(s_restart(path)));
3169a747e4fSDavid du Colombier 	if(nci->rsys && *nci->rsys){
3177dd7cddfSDavid du Colombier 		cp = s_to_c(lpath);
3187dd7cddfSDavid du Colombier 		if(strncmp(cp, "[]!", 3) == 0){
3197dd7cddfSDavid du Colombier found:
3207dd7cddfSDavid du Colombier 			s_append(path, "[");
3219a747e4fSDavid du Colombier 			s_append(path, nci->rsys);
3227dd7cddfSDavid du Colombier 			s_append(path, "]!");
3237dd7cddfSDavid du Colombier 			s_append(path, cp+3);
3247dd7cddfSDavid du Colombier 			s_terminate(path);
3257dd7cddfSDavid du Colombier 			s_free(lpath);
3267dd7cddfSDavid du Colombier 			return 0;
3277dd7cddfSDavid du Colombier 		}
3287dd7cddfSDavid du Colombier 		cp = strchr(cp,'!');			/* skip our domain and check next */
3297dd7cddfSDavid du Colombier 		if(cp++ && strncmp(cp, "[]!", 3) == 0)
3307dd7cddfSDavid du Colombier 			goto found;
3317dd7cddfSDavid du Colombier 	}
3329a747e4fSDavid du Colombier 
3339a747e4fSDavid du Colombier 	/* if mail is from a trusted IP addr, allow it to forward */
3347dd7cddfSDavid du Colombier 	if(trusted) {
3357dd7cddfSDavid du Colombier 		s_free(lpath);
3367dd7cddfSDavid du Colombier 		return 0;
3377dd7cddfSDavid du Colombier 	}
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier 	/* sender is untrusted; ensure receiver is in one of our domains */
3407dd7cddfSDavid du Colombier 	for(cp = s_to_c(lpath); *cp; cp++)		/* convert receiver lc */
3417dd7cddfSDavid du Colombier 		*cp = tolower(*cp);
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier 	for(s = s_to_c(lpath); cp = strchr(s, '!'); s = cp+1){
3447dd7cddfSDavid du Colombier 		*cp = 0;
345*6b6b9ac8SDavid du Colombier 		if(!isourdom(s)){
3467dd7cddfSDavid du Colombier 			s_free(lpath);
3477dd7cddfSDavid du Colombier 			return 1;
3487dd7cddfSDavid du Colombier 		}
3497dd7cddfSDavid du Colombier 	}
3507dd7cddfSDavid du Colombier 	s_free(lpath);
3517dd7cddfSDavid du Colombier 	return 0;
3527dd7cddfSDavid du Colombier }
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier int
355*6b6b9ac8SDavid du Colombier masquerade(String *path, char *him)
356*6b6b9ac8SDavid du Colombier {
357*6b6b9ac8SDavid du Colombier 	char *cp, *s;
358*6b6b9ac8SDavid du Colombier 	String *lpath;
359*6b6b9ac8SDavid du Colombier 	int rv = 0;
360*6b6b9ac8SDavid du Colombier 
361*6b6b9ac8SDavid du Colombier 	if(debug)
362*6b6b9ac8SDavid du Colombier 		fprint(2, "masquerade(%s)\n", s_to_c(path));
363*6b6b9ac8SDavid du Colombier 
364*6b6b9ac8SDavid du Colombier 	if(trusted)
365*6b6b9ac8SDavid du Colombier 		return 0;
366*6b6b9ac8SDavid du Colombier 	if(path == nil)
367*6b6b9ac8SDavid du Colombier 		return 0;
368*6b6b9ac8SDavid du Colombier 
369*6b6b9ac8SDavid du Colombier 	lpath = s_copy(s_to_c(path));
370*6b6b9ac8SDavid du Colombier 
371*6b6b9ac8SDavid du Colombier 	/* sender is untrusted; ensure receiver is in one of our domains */
372*6b6b9ac8SDavid du Colombier 	for(cp = s_to_c(lpath); *cp; cp++)		/* convert receiver lc */
373*6b6b9ac8SDavid du Colombier 		*cp = tolower(*cp);
374*6b6b9ac8SDavid du Colombier 
375*6b6b9ac8SDavid du Colombier 	/* scan first element of ! or last element of @ paths */
376*6b6b9ac8SDavid du Colombier 	s = s_to_c(lpath);
377*6b6b9ac8SDavid du Colombier 	if((cp = strchr(s, '!')) != nil){
378*6b6b9ac8SDavid du Colombier 		*cp = 0;
379*6b6b9ac8SDavid du Colombier 		if(isourdom(s))
380*6b6b9ac8SDavid du Colombier 			rv = 1;
381*6b6b9ac8SDavid du Colombier 	} else if((cp = strrchr(s, '@')) != nil){
382*6b6b9ac8SDavid du Colombier 		if(isourdom(cp+1))
383*6b6b9ac8SDavid du Colombier 			rv = 1;
384*6b6b9ac8SDavid du Colombier 	} else {
385*6b6b9ac8SDavid du Colombier 		if(isourdom(him))
386*6b6b9ac8SDavid du Colombier 			rv = 1;
387*6b6b9ac8SDavid du Colombier 	}
388*6b6b9ac8SDavid du Colombier 
389*6b6b9ac8SDavid du Colombier 	s_free(lpath);
390*6b6b9ac8SDavid du Colombier 	return rv;
391*6b6b9ac8SDavid du Colombier }
392*6b6b9ac8SDavid du Colombier 
393*6b6b9ac8SDavid du Colombier int
3947dd7cddfSDavid du Colombier cidrcheck(char *cp)
3957dd7cddfSDavid du Colombier {
3967dd7cddfSDavid du Colombier 	char *p;
3977dd7cddfSDavid du Colombier 	ulong a, m;
3987dd7cddfSDavid du Colombier 	uchar addr[IPv4addrlen];
3997dd7cddfSDavid du Colombier 	uchar mask[IPv4addrlen];
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 	if(peerip == 0)
4027dd7cddfSDavid du Colombier 		return 0;
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier 		/* parse a list of CIDR addresses comparing each to the peer IP addr */
4057dd7cddfSDavid du Colombier 	while(cp && *cp){
4067dd7cddfSDavid du Colombier 		v4parsecidr(addr, mask, cp);
4077dd7cddfSDavid du Colombier 		a = nhgetl(addr);
4087dd7cddfSDavid du Colombier 		m = nhgetl(mask);
4097dd7cddfSDavid du Colombier 		/*
4107dd7cddfSDavid du Colombier 		 * if a mask isn't specified, we build a minimal mask
4117dd7cddfSDavid du Colombier 		 * instead of using the default mask for that net.  in this
4127dd7cddfSDavid du Colombier 		 * case we never allow a class A mask (0xff000000).
4137dd7cddfSDavid du Colombier 		 */
4147dd7cddfSDavid du Colombier 		if(strchr(cp, '/') == 0){
4157dd7cddfSDavid du Colombier 			m = 0xff000000;
4167dd7cddfSDavid du Colombier 			p = cp;
4177dd7cddfSDavid du Colombier 			for(p = strchr(p, '.'); p && p[1]; p = strchr(p+1, '.'))
4187dd7cddfSDavid du Colombier 					m = (m>>8)|0xff000000;
4197dd7cddfSDavid du Colombier 
4207dd7cddfSDavid du Colombier 			/* force at least a class B */
4217dd7cddfSDavid du Colombier 			m |= 0xffff0000;
4227dd7cddfSDavid du Colombier 		}
4237dd7cddfSDavid du Colombier 		if((peerip&m) == a)
4247dd7cddfSDavid du Colombier 			return 1;
4257dd7cddfSDavid du Colombier 		cp += strlen(cp)+1;
4267dd7cddfSDavid du Colombier 	}
4277dd7cddfSDavid du Colombier 	return 0;
4287dd7cddfSDavid du Colombier }
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier char*
4317dd7cddfSDavid du Colombier dumpfile(char *sender)
4327dd7cddfSDavid du Colombier {
4337dd7cddfSDavid du Colombier 	int i, fd;
4347dd7cddfSDavid du Colombier 	ulong h;
4357dd7cddfSDavid du Colombier 	static char buf[512];
4367dd7cddfSDavid du Colombier 	char *cp;
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier 	if (sflag == 1){
4397dd7cddfSDavid du Colombier 		cp = ctime(time(0));
4407dd7cddfSDavid du Colombier 		cp[7] = 0;
4417dd7cddfSDavid du Colombier 		if(cp[8] == ' ')
4427dd7cddfSDavid du Colombier 			sprint(buf, "%s/queue.dump/%s%c", SPOOL, cp+4, cp[9]);
4437dd7cddfSDavid du Colombier 		else
4447dd7cddfSDavid du Colombier 			sprint(buf, "%s/queue.dump/%s%c%c", SPOOL, cp+4, cp[8], cp[9]);
4457dd7cddfSDavid du Colombier 		cp = buf+strlen(buf);
4467dd7cddfSDavid du Colombier 		if(access(buf, 0) < 0 && sysmkdir(buf, 0777) < 0)
4477dd7cddfSDavid du Colombier 			return "/dev/null";
4487dd7cddfSDavid du Colombier 		h = 0;
4497dd7cddfSDavid du Colombier 		while(*sender)
4507dd7cddfSDavid du Colombier 			h = h*257 + *sender++;
4517dd7cddfSDavid du Colombier 		for(i = 0; i < 50; i++){
4527dd7cddfSDavid du Colombier 			h += lrand();
4537dd7cddfSDavid du Colombier 			sprint(cp, "/%lud", h);
4547dd7cddfSDavid du Colombier 			if(access(buf, 0) >= 0)
4557dd7cddfSDavid du Colombier 				continue;
45659cc4ca5SDavid du Colombier 			fd = syscreate(buf, ORDWR, 0666);
4577dd7cddfSDavid du Colombier 			if(fd >= 0){
4587dd7cddfSDavid du Colombier 				if(debug)
4597dd7cddfSDavid du Colombier 					fprint(2, "saving in %s\n", buf);
4607dd7cddfSDavid du Colombier 				close(fd);
4617dd7cddfSDavid du Colombier 				return buf;
4627dd7cddfSDavid du Colombier 			}
4637dd7cddfSDavid du Colombier 		}
4647dd7cddfSDavid du Colombier 	}
4657dd7cddfSDavid du Colombier 	return "/dev/null";
4667dd7cddfSDavid du Colombier }
46780ee5cbfSDavid du Colombier 
46880ee5cbfSDavid du Colombier int
46980ee5cbfSDavid du Colombier recipok(char *user)
47080ee5cbfSDavid du Colombier {
47180ee5cbfSDavid du Colombier 	char *cp, *p, c;
47280ee5cbfSDavid du Colombier 	char buf[512];
47380ee5cbfSDavid du Colombier 	int n;
47480ee5cbfSDavid du Colombier 	Biobuf *bp;
47580ee5cbfSDavid du Colombier 
47680ee5cbfSDavid du Colombier 	snprint(buf, sizeof(buf), "%s/names.blocked", UPASLIB);
47780ee5cbfSDavid du Colombier 	bp = sysopen(buf, "r", 0);
47880ee5cbfSDavid du Colombier 	if(bp == 0)
47980ee5cbfSDavid du Colombier 		return 1;
48080ee5cbfSDavid du Colombier 	for(;;){
48180ee5cbfSDavid du Colombier 		cp = Brdline(bp, '\n');
48280ee5cbfSDavid du Colombier 		if(cp == 0)
48380ee5cbfSDavid du Colombier 			break;
48480ee5cbfSDavid du Colombier 		n = Blinelen(bp);
48580ee5cbfSDavid du Colombier 		cp[n-1] = 0;
48680ee5cbfSDavid du Colombier 
48780ee5cbfSDavid du Colombier 		while(*cp == ' ' || *cp == '\t')
48880ee5cbfSDavid du Colombier 			cp++;
48980ee5cbfSDavid du Colombier 		for(p = cp; c = *p; p++){
49080ee5cbfSDavid du Colombier 			if(c == '#')
49180ee5cbfSDavid du Colombier 				break;
49280ee5cbfSDavid du Colombier 			if(c == ' ' || c == '\t')
49380ee5cbfSDavid du Colombier 				break;
49480ee5cbfSDavid du Colombier 		}
49580ee5cbfSDavid du Colombier 		if(p > cp){
49680ee5cbfSDavid du Colombier 			*p = 0;
49780ee5cbfSDavid du Colombier 			if(cistrcmp(user, cp) == 0){
49880ee5cbfSDavid du Colombier 				Bterm(bp);
49980ee5cbfSDavid du Colombier 				return 0;
50080ee5cbfSDavid du Colombier 			}
50180ee5cbfSDavid du Colombier 		}
50280ee5cbfSDavid du Colombier 	}
50380ee5cbfSDavid du Colombier 	Bterm(bp);
50480ee5cbfSDavid du Colombier 	return 1;
505d9306527SDavid du Colombier }
506d9306527SDavid du Colombier 
507d9306527SDavid du Colombier /*
508d9306527SDavid du Colombier  *  a user can opt out of spam filtering by creating
509d9306527SDavid du Colombier  *  a file in his mail directory named 'nospamfiltering'.
510d9306527SDavid du Colombier  */
511d9306527SDavid du Colombier int
512d9306527SDavid du Colombier optoutofspamfilter(char *addr)
513d9306527SDavid du Colombier {
514d9306527SDavid du Colombier 	char *p, *f;
515d9306527SDavid du Colombier 	int rv;
516d9306527SDavid du Colombier 
517d9306527SDavid du Colombier 	p = strchr(addr, '!');
518d9306527SDavid du Colombier 	if(p)
519d9306527SDavid du Colombier 		p++;
520d9306527SDavid du Colombier 	else
521d9306527SDavid du Colombier 		p = addr;
522d9306527SDavid du Colombier 
523d9306527SDavid du Colombier 
524d9306527SDavid du Colombier 	rv = 0;
525d9306527SDavid du Colombier 	f = smprint("/mail/box/%s/nospamfiltering", p);
526d9306527SDavid du Colombier 	if(f != nil){
527d9306527SDavid du Colombier 		rv = access(f, 0)==0;
528d9306527SDavid du Colombier 		free(f);
529d9306527SDavid du Colombier 	}
530d9306527SDavid du Colombier 
531d9306527SDavid du Colombier 	return rv;
53280ee5cbfSDavid du Colombier }
533