Additional info regarding this patch can be found at http://www.tnpi.biz/internet/mail/toaster/patches/tcpserver-mysql.shtml v1.2 - 2004.08.01 same patch, but entirely in unified diff format for folks whose patch program is nit picky. v1.1 - 2004.05.29 added RBLSMTPD to IPs in MySQL table so that clients that have authenticated override any IP blacklists (like SORBS) diff -urN ucspi-tcp-0.88.dist/Makefile ucspi-tcp-0.88/Makefile --- ucspi-tcp-0.88.dist/Makefile Sat Mar 18 10:18:42 2000 +++ ucspi-tcp-0.88/Makefile Mon Aug 2 20:36:50 2004 @@ -513,6 +513,10 @@ rules.h stralloc.h ./compile rules.c +db.o: \ +compile db.c db.h + ./compile db.c + scan_ulong.o: \ compile scan_ulong.c scan.h ./compile scan_ulong.c @@ -742,16 +746,16 @@ ./compile tcprulescheck.c tcpserver: \ -load tcpserver.o rules.o remoteinfo.o timeoutconn.o cdb.a dns.a \ +load tcpserver.o rules.o db.o remoteinfo.o timeoutconn.o cdb.a dns.a \ time.a unix.a byte.a socket.lib - ./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \ + ./load tcpserver rules.o db.o remoteinfo.o timeoutconn.o cdb.a \ dns.a time.a unix.a byte.a `cat socket.lib` tcpserver.o: \ compile tcpserver.c uint16.h str.h byte.h fmt.h scan.h ip4.h fd.h \ exit.h env.h prot.h open.h wait.h readwrite.h stralloc.h gen_alloc.h \ alloc.h buffer.h error.h strerr.h sgetopt.h subgetopt.h pathexec.h \ -socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h \ +socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h db.h \ stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \ taia.h ./compile tcpserver.c diff -urN ucspi-tcp-0.88.dist/conf-cc ucspi-tcp-0.88/conf-cc --- ucspi-tcp-0.88.dist/conf-cc Sat Mar 18 10:18:42 2000 +++ ucspi-tcp-0.88/conf-cc Mon Aug 2 20:36:50 2004 @@ -1,3 +1,3 @@ -gcc -O2 +gcc -O2 -I/usr/local/include/mysql This will be used to compile .c files. diff -urN ucspi-tcp-0.88.dist/conf-ld ucspi-tcp-0.88/conf-ld --- ucspi-tcp-0.88.dist/conf-ld Sat Mar 18 10:18:42 2000 +++ ucspi-tcp-0.88/conf-ld Mon Aug 2 20:36:50 2004 @@ -1,3 +1,3 @@ -gcc -s +gcc -s -I/usr/local/include/mysql -L/usr/local/lib/mysql -lmysqlclient This will be used to link .o files into an executable. diff -urN ucspi-tcp-0.88.dist/db.c ucspi-tcp-0.88/db.c --- ucspi-tcp-0.88.dist/db.c Wed Dec 31 19:00:00 1969 +++ ucspi-tcp-0.88/db.c Mon Aug 2 20:36:50 2004 @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include "db.h" + +/* +server sql.mailserver.com +port 3306 +database vpopmail +table relay +user vpopmail +pass secret +time 1800 +*/ +#define MAX_QUERY_STRING 160 + +MYSQL *dbh=NULL; + +char db_database[256]; +char db_host[256]; +char db_table[256]; +char db_user[256]; +char db_password[256]; +int db_port=-1; +int pop_timeout; + +extern int verbosity; + +int open_db(char *database, char *host, int port, char *username, char *password) +{ + MYSQL *tmp; + + if (dbh != NULL) { + mysql_close(dbh); + dbh = NULL; + } + dbh = (MYSQL *)mysql_init(NULL); + if (dbh == NULL) + { + fprintf(stderr,"MYSQL Init Error:\n"); + return -1; + } + + tmp = mysql_real_connect(dbh, host, username, password, database, port, NULL,0); + + if (!tmp) + { + fprintf(stderr,"MYSQL Error: %s\n",mysql_error(dbh)); + return -1; + } + + return 0; +} + +int check_db(char *remoteip) { + char query[MAX_QUERY_STRING]; + int num_rows = 0; + int ret = -1; + MYSQL_RES *res; + + snprintf(query,MAX_QUERY_STRING,"SELECT timestamp FROM %s WHERE ip_addr='%s' AND timestamp>(UNIX_TIMESTAMP()-%d)", db_table, remoteip, pop_timeout); + + ret = mysql_query(dbh,query); + res = mysql_store_result(dbh); + num_rows = mysql_affected_rows(dbh); + mysql_free_result(res); + + if (ret) { + char err_str[256]; + + snprintf(err_str,255,"-%s-",mysql_error(dbh)); + fprintf(stderr,"%s",err_str); + if(strstr("server has gone away",err_str)) { + db_close(); + db_ping(); + + ret = mysql_query(dbh,query); + if (ret) { + return -1; + } + } else { + db_close(); + db_ping(); + + ret = mysql_query(dbh,query); + if (ret) { + return -1; + } + } + } + if (verbosity >= 3) { + fprintf(stderr,"QUERY(err:%d/rows:%d): %s\n",ret,num_rows,query); /* */ + } + + if(num_rows>0) { + return 0; + } else { + return 1; + } +} + +void db_close() +{ + mysql_close(dbh); + dbh=NULL; + + if (verbosity >= 2) { + fprintf(stderr,"db_close() called!\n"); + } +} + +void db_ping() +{ + if(dbh==NULL || mysql_ping(dbh)) { + if (verbosity >= 2) { + fprintf(stderr,"db_ping() is re-calling open_db!\n"); + } + open_db(db_database,db_host,db_port,db_user,db_password); + } +} + diff -urN ucspi-tcp-0.88.dist/db.h ucspi-tcp-0.88/db.h --- ucspi-tcp-0.88.dist/db.h Wed Dec 31 19:00:00 1969 +++ ucspi-tcp-0.88/db.h Mon Aug 2 20:36:50 2004 @@ -0,0 +1,17 @@ +#ifndef _DB_ +#define _DB_ + +extern char db_database[256]; +extern char db_host[256]; +extern char db_table[256]; +extern char db_user[256]; +extern char db_password[256]; +extern int db_port; +extern int pop_timeout; + +int open_db(char *database, char *host, int port, char *username, char *password); +int check_db(char *remoteip); +void db_ping(); +void db_close(); + +#endif diff -urN ucspi-tcp-0.88.dist/rblsmtpd.c ucspi-tcp-0.88/rblsmtpd.c --- ucspi-tcp-0.88.dist/rblsmtpd.c Sat Mar 18 10:18:42 2000 +++ ucspi-tcp-0.88/rblsmtpd.c Mon Aug 2 20:36:50 2004 @@ -60,16 +60,54 @@ void rbl(char *base) { + int i; + char *altreply = 0; if (decision) return; if (!stralloc_copy(&tmp,&ip_reverse)) nomem(); + i = str_chr(base, ':'); + if (base[i]) { + base[i] = 0; + altreply = base+i+1; + } if (!stralloc_cats(&tmp,base)) nomem(); - if (dns_txt(&text,&tmp) == -1) { - flagmustnotbounce = 1; - if (flagfailclosed) { - if (!stralloc_copys(&text,"temporary RBL lookup error")) nomem(); - decision = 2; + if (altreply) { + if (dns_ip4(&text,&tmp) == -1) { + flagmustnotbounce = 1; + if (flagfailclosed) { + if (!stralloc_copys(&text,"temporary RBL lookup error")) nomem(); + decision = 2; + } + return; + } + if (text.len) { + if(!stralloc_copys(&text, "")) nomem(); + while(*altreply) { + char *x; + i = str_chr(altreply, '%'); + if(!stralloc_catb(&text, altreply, i)) nomem(); + if(altreply[i] && + altreply[i+1]=='I' && + altreply[i+2]=='P' && + altreply[i+3]=='%') { + if(!stralloc_catb(&text, ip_env, str_len(ip_env))) nomem(); + altreply+=i+4; + } else if(altreply[i]) { + if(!stralloc_cats(&text, "%")) nomem(); + altreply+=i+1; + } else { + altreply+=i; + } + } + } + } else { + if (dns_txt(&text,&tmp) == -1) { + flagmustnotbounce = 1; + if (flagfailclosed) { + if (!stralloc_copys(&text,"temporary RBL lookup error")) nomem(); + decision = 2; + } + return; } - return; } if (text.len) if (flagrblbounce) diff -urN ucspi-tcp-0.88.dist/tcpserver.c ucspi-tcp-0.88/tcpserver.c --- ucspi-tcp-0.88.dist/tcpserver.c Sat Mar 18 10:18:42 2000 +++ ucspi-tcp-0.88/tcpserver.c Mon Aug 2 20:36:50 2004 @@ -1,3 +1,4 @@ +#include #include #include #include @@ -25,12 +26,14 @@ #include "ndelay.h" #include "remoteinfo.h" #include "rules.h" +#include "db.h" #include "sig.h" #include "dns.h" int verbosity = 1; int flagkillopts = 1; int flagdelay = 1; +int usemysql = 0; char *banner = ""; int flagremoteinfo = 1; int flagremotehost = 1; @@ -109,6 +112,10 @@ { strerr_die4sys(111,DROP,"unable to read ",fnrules,": "); } +void drop_db(void) +{ + strerr_die4sys(111,DROP,"unable to verify DB ",db_database,": "); +} void found(char *data,unsigned int datalen) { @@ -198,8 +205,19 @@ } env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); - if (fnrules) { + if(usemysql) { + if(flagdeny==2) { + /* drop_db(); */ + } else if(!flagdeny) { + env("RELAYCLIENT",""); + env("RBLSMTPD",""); + } + flagdeny=0; + } + + if(fnrules) { int fdrules; + fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); @@ -240,7 +258,7 @@ { strerr_warn1("\ tcpserver: usage: tcpserver \ -[ -1UXpPhHrRoOdDqQv ] \ +[ -1UXpPhHrRoOdDqQvS ] \ [ -c limit ] \ [ -x rules.cdb ] \ [ -B banner ] \ @@ -300,7 +318,7 @@ int s; int t; - while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof) + while ((opt = getopt(argc,argv,"dDvqQhHrR1UXSx:t:u:g:l:b:B:c:pPoO")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; @@ -327,6 +345,7 @@ case 'g': scan_ulong(optarg,&gid); break; case '1': flag1 = 1; break; case 'l': localhost = optarg; break; + case 'S': usemysql = 1; break; default: usage(); } argc -= optind; @@ -398,6 +417,7 @@ for (;;) { while (numchildren >= limit) sig_pause(); + flagdeny=0; sig_unblock(sig_child); t = socket_accept4(s,remoteip,&remoteport); sig_block(sig_child); @@ -405,6 +425,76 @@ if (t == -1) continue; ++numchildren; printstatus(); + if(usemysql) { + int ret; + + remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0; + + if(db_port==-1) { + FILE *fp; + + if(fp=fopen("/var/qmail/control/sql","r")) { + char line[256]; + char tag[256]; + char value[256]; + + while(fgets(line,256,fp)) { + char *comment; + + if(comment=strchr(line,'#')) { + *comment='\0'; + } + if(sscanf(line,"%s\t%s\n", tag, value) != 2) continue; + /* fprintf(stderr,"Warning: got Line: [%s]\n",line); */ + + /* + server sql.domain.com + port 3306 + database vpopmail + table relay + user vpopmail + pass secret + time 1800 + */ + if(!strcasecmp(tag,"server")) { + strcpy(db_host,value); + } else if(!strcasecmp(tag,"port")) { + db_port = atoi(value); + } else if(!strcasecmp(tag,"database")) { + strcpy(db_database,value); + } else if(!strcasecmp(tag,"table")) { + strcpy(db_table,value); + } else if(!strcasecmp(tag,"user")) { + strcpy(db_user,value); + } else if(!strcasecmp(tag,"pass")) { + strcpy(db_password,value); + } else if(!strcasecmp(tag,"time")) { + pop_timeout=atoi(value); + } else { + fprintf(stderr,"Warning: Bad sql: TAG: [%s] VALUE: [%s]\n",tag,value); + } + } + } + if(db_port==-1) { + fprintf(stderr,"Error: Failed to read /var/qmail/control/sql\n"); + db_port==-2; + } else { + fclose(fp); + } + if (verbosity >= 2) { + fprintf(stderr,"db_port set to: [%d]\n", db_port); + } + } + if(db_port>=0) { + db_ping(); + if((ret=check_db(remoteipstr))==-1) { + flagdeny=2; + } else if(ret) { + flagdeny=1; + } + } + } + switch(fork()) { case 0: close(s);