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