Jan Mojzis Global setup ============= echo "192.168.1.20:60000" > /var/qmail/control/postgrey ... done Per IP setup ============ echo "192.168.1.:allow,POSTGREY="192.168.1.20:60000" >> /etc/tcp.smtp tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp ... done diff -uNr qmail-1.03/hier.c qmail-1.03.postgrey/hier.c --- qmail-1.03/hier.c 1998-06-15 12:53:16.000000000 +0200 +++ qmail-1.03.postgrey/hier.c 2008-09-21 13:16:14.323441197 +0200 @@ -104,6 +104,7 @@ c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700); c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711); c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711); + c(auto_qmail,"bin","qmail-postgrey",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711); c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711); c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711); diff -uNr qmail-1.03/Makefile qmail-1.03.postgrey/Makefile --- qmail-1.03/Makefile 1998-06-15 12:53:16.000000000 +0200 +++ qmail-1.03.postgrey/Makefile 2008-09-21 13:15:12.275563447 +0200 @@ -808,7 +808,7 @@ forward preline condredirect bouncesaying except maildirmake \ maildir2mbox maildirwatch qail elq pinq idedit install-big install \ instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ -binm3 binm3+df +binm3 binm3+df qmail-postgrey load: \ make-load warn-auto.sh systype @@ -1556,6 +1556,17 @@ exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h ./compile qmail-smtpd.c +qmail-postgrey.o: \ +compile qmail-postgrey.c stralloc.h + ./compile qmail-postgrey.c + +qmail-postgrey: \ +load qmail-postgrey.o timeoutread.o timeoutwrite.o timeoutconn.o ip.o \ +stralloc.a alloc.a case.a str.a error.a fs.a ndelay.a + ./load qmail-postgrey timeoutread.o timeoutwrite.o \ + timeoutconn.o ip.o stralloc.a alloc.a case.a str.a error.a fs.a \ + ndelay.a `cat socket.lib` + qmail-start: \ load qmail-start.o prot.o fd.a auto_uids.o ./load qmail-start prot.o fd.a auto_uids.o diff -uNr qmail-1.03/qmail-postgrey.c qmail-1.03.postgrey/qmail-postgrey.c --- qmail-1.03/qmail-postgrey.c 1970-01-01 01:00:00.000000000 +0100 +++ qmail-1.03.postgrey/qmail-postgrey.c 2008-09-21 13:15:12.283563947 +0200 @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include "stralloc.h" +#include "error.h" +#include "ip.h" +#include "case.h" +#include "str.h" +#include "exit.h" + +#define CT 10 /* Connect timeout */ +#define WT 10 /* Write timeout */ +#define RT 10 /* Read timeout */ + +struct ip_address ip; +int port = 60000; /* default port */ +int s; +int n; +unsigned int i; +char *ipport; +stralloc query = {0}; +char buf[64]; + + +int main(int argc, char *argv[]){ + + + if (argc != 6){ + printf("usage:\n"); + printf("%s ip:port sender recipient client_address client_name\n", argv[0]); + printf("\n"); + fflush(stdout); + _exit(1); + } + + if (!stralloc_copys(&query,"request=smtpd_access_policy\nclient_address="))_exit(1); + if (!stralloc_cats(&query,argv[4]))_exit(1); + if (!stralloc_cats(&query,"\nclient_name="))_exit(1); + if (!stralloc_cats(&query,argv[5]))_exit(1); + if (!stralloc_cats(&query,"\nsender="))_exit(1); + if (!stralloc_cats(&query,argv[2]))_exit(1); + if (!stralloc_cats(&query,"\nrecipient="))_exit(1); + if (!stralloc_cats(&query,argv[3]))_exit(1); + if (!stralloc_cats(&query,"\n\n"))_exit(1); + + /* scan ip and port */ + ipport=argv[1]; + if (!ip_scan(ipport,&ip)) _exit(1); + i = str_chr(ipport,':'); + if (ipport[i]){ + scan_ulong(ipport + i + 1, &port); + } + + /* create tcp socket */ + s = socket(AF_INET,SOCK_STREAM,0); + if (s == -1)_exit(1); + + /* connect to postgrey server */ + if (timeoutconn(s,&ip,port,CT) != 0) { + close(s); + _exit(1); + } + + /* write request */ + do{ + n = timeoutwrite(WT, s, query.s, query.len); + }while(n == -1 && errno == error_intr); + if (n != query.len){close(s);_exit(1);} + + /* read response */ + do{ + n = timeoutread(RT, s, buf, sizeof buf); + }while(n == -1 && errno == error_intr); + if (n == -1){close(s);_exit(1);} + close(s); + + if (n >= 12) + if (!case_diffb(buf,12,"action=dunno")) _exit(0); + + if (n >= 14) + if (!case_diffb(buf,14,"action=prepend")) _exit(0); + + if (n >= 22) + if (!case_diffb(buf,22,"action=defer_if_permit")) _exit(10); + + _exit(1); +} diff -uNr qmail-1.03/qmail-smtpd.c qmail-1.03.postgrey/qmail-smtpd.c --- qmail-1.03/qmail-smtpd.c 1998-06-15 12:53:16.000000000 +0200 +++ qmail-1.03.postgrey/qmail-smtpd.c 2008-09-21 13:16:34.816721947 +0200 @@ -19,6 +19,8 @@ #include "env.h" #include "now.h" #include "exit.h" +#include "fork.h" +#include "wait.h" #include "rcpthosts.h" #include "timeoutread.h" #include "timeoutwrite.h" @@ -58,6 +60,7 @@ void err_noop() { out("250 ok\r\n"); } void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); } void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } +void err_greylisted() { out("450 greylisted (#4.3.0)\r\n"); } stralloc greeting = {0}; @@ -91,6 +94,9 @@ fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0; } +int pgreyok = 0; +stralloc pgrey = {0}; + int liphostok = 0; stralloc liphost = {0}; int bmfok = 0; @@ -112,6 +118,12 @@ if (rcpthosts_init() == -1) die_control(); + pgreyok = control_rldef(&pgrey,"control/postgrey",0,(char *) 0); + if (pgreyok == -1) die_control(); + x = env_get("POSTGREY"); + if (x) if (!stralloc_copys(&pgrey,x)) die_nomem(); + if (!stralloc_append(&pgrey,"")) die_nomem(); + bmfok = control_readfile(&bmf,"control/badmailfrom",0); if (bmfok == -1) die_control(); if (bmfok) @@ -256,8 +268,10 @@ if (!stralloc_cats(&addr,relayclient)) die_nomem(); if (!stralloc_0(&addr)) die_nomem(); } - else + else{ if (!addrallowed()) { err_nogateway(); return; } + if ((pgreyok) && (postgrey_scanner() == 1)){ err_greylisted(); return;} + } if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); @@ -265,6 +279,35 @@ } +int postgrey_scanner() +{ + int child; + int wstat; + + char *postgrey_scannerarg[] = { "bin/qmail-postgrey" , pgrey.s, mailfrom.s, addr.s, remoteip, remotehost, 0 }; + + switch(child = vfork()) { + case -1: + return -1; + case 0: + execv(*postgrey_scannerarg,postgrey_scannerarg); + _exit(1); + } + + wait_pid(&wstat,child); + if (wait_crashed(wstat)) { + return -1; + } + + switch(wait_exitcode(wstat)) { + case 10: + return 1; + default: + return 0; + } +} + + int saferead(fd,buf,len) int fd; char *buf; int len; { int r;