# This patch is a combination of... # # ucspi-tcp-0.88-errno.patch # fix error.h to work with glibc 2.3 # ucspi-rss.diff # makes rblsmtpd recognize A records instead of TXT records # ucspi-tcp-ssl-20020705.patch # add SSL functionality to tcpserver # ucspi-tcp-0.88-periplimit.6.patch # set a limit on how many concurrent connections may come from any # one IP address. # MODIFICATION to above-listed per-ip-limit patch # use "-i #" instead of "-s #" to specify the per-IP limit. # modification needed since SSL patch also uses "-s" # MODIFICATION to Makefile # add /usr/kerberos/include ... necessary for systems where openssl is # linked with kerberos, such as WhiteBox or RedHat. # # John Simpson 2004-07-05 # http://www.jms1.net/ucsp-tcp/ diff -urN ucspi-tcp-0.88-vanilla/Makefile ucspi-tcp-0.88-patched/Makefile --- ucspi-tcp-0.88-vanilla/Makefile 2000-03-18 10:18:42.000000000 -0500 +++ ucspi-tcp-0.88-patched/Makefile 2004-07-05 01:50:28.000000000 -0400 @@ -1,5 +1,13 @@ # Don't edit Makefile! Use conf-* for configuration. +DEFINES=-DWITH_SSL +#add -DWITH_SSL to enable ssl support + +# LIBS for additional libraries and INCS for additional includes +LIBS=-lcrypto -lssl +INCS=-I/usr/kerberos/include +OPENSSLBIN=openssl + SHELL=/bin/sh default: it @@ -151,6 +159,10 @@ > choose chmod 755 choose +clean: \ +TARGETS + rm -f `cat TARGETS` + commands.o: \ compile commands.c buffer.h stralloc.h gen_alloc.h str.h case.h \ commands.h @@ -745,7 +757,7 @@ load tcpserver.o rules.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 \ - dns.a time.a unix.a byte.a `cat socket.lib` + dns.a time.a unix.a byte.a $(LIBS) `cat socket.lib` tcpserver.o: \ compile tcpserver.c uint16.h str.h byte.h fmt.h scan.h ip4.h fd.h \ @@ -753,8 +765,8 @@ 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 \ stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \ -taia.h - ./compile tcpserver.c +taia.h uint32.h + ./compile $(DEFINES) $(INCS) tcpserver.c time.a: \ makelib iopause.o tai_pack.o taia_add.o taia_approx.o taia_frac.o \ @@ -835,3 +847,18 @@ | sed s}HOME}"`head -1 conf-home`"}g \ > who@ chmod 755 who@ + +cert: + ${OPENSSLBIN} req -new -x509 -nodes \ + -out cert.pem -days 366 \ + -keyout cert.pem + +cert-req: + ${OPENSSLBIN} req -new -nodes \ + -out req.pem \ + -keyout cert.pem + @echo + @echo "Send req.pem to your CA to obtain signed_req.pem, and do:" + @echo "cat signed_req.pem >> `head -1 conf-qmail`/control/cert.pem" + + diff -urN ucspi-tcp-0.88-vanilla/error.h ucspi-tcp-0.88-patched/error.h --- ucspi-tcp-0.88-vanilla/error.h 2000-03-18 10:18:42.000000000 -0500 +++ ucspi-tcp-0.88-patched/error.h 2004-07-05 01:50:19.000000000 -0400 @@ -1,7 +1,8 @@ #ifndef ERROR_H #define ERROR_H -extern int errno; +/* extern int errno; */ +#include extern int error_intr; extern int error_nomem; diff -urN ucspi-tcp-0.88-vanilla/rblsmtpd.c ucspi-tcp-0.88-patched/rblsmtpd.c --- ucspi-tcp-0.88-vanilla/rblsmtpd.c 2000-03-18 10:18:42.000000000 -0500 +++ ucspi-tcp-0.88-patched/rblsmtpd.c 2004-07-05 01:44:18.000000000 -0400 @@ -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-vanilla/tcpserver.c ucspi-tcp-0.88-patched/tcpserver.c --- ucspi-tcp-0.88-vanilla/tcpserver.c 2000-03-18 10:18:42.000000000 -0500 +++ ucspi-tcp-0.88-patched/tcpserver.c 2004-07-05 01:46:40.000000000 -0400 @@ -1,7 +1,9 @@ #include #include #include +#include #include "uint16.h" +#include "uint32.h" #include "str.h" #include "byte.h" #include "fmt.h" @@ -36,6 +38,13 @@ int flagremotehost = 1; int flagparanoid = 0; unsigned long timeout = 26; +#ifdef WITH_SSL +int flagssl = 0; +struct stralloc certfile = {0}; +#define CERTFILE "./cert.pem" + +void translate(SSL*, int, int, unsigned int); +#endif static stralloc tcpremoteinfo; @@ -238,10 +247,12 @@ void usage(void) { +#ifndef WITH_SSL strerr_warn1("\ tcpserver: usage: tcpserver \ [ -1UXpPhHrRoOdDqQv ] \ [ -c limit ] \ +[ -i perip limit ] \ [ -x rules.cdb ] \ [ -B banner ] \ [ -g gid ] \ @@ -250,12 +261,43 @@ [ -l localname ] \ [ -t timeout ] \ host port program",0); +#else + strerr_warn1("\ +tcpserver: usage: tcpserver \ +[ -1UXpPhHrRoOdDqQsSv ] \ +[ -c limit ] \ +[ -x rules.cdb ] \ +[ -B banner ] \ +[ -g gid ] \ +[ -u uid ] \ +[ -b backlog ] \ +[ -l localname ] \ +[ -t timeout ] \ +[ -n certfile ] \ +host port program",0); +#endif _exit(100); } unsigned long limit = 40; +unsigned long periplimit = 0; unsigned long numchildren = 0; +typedef struct +{ + pid_t pid; + int offset; +} connections; + +typedef struct +{ + uint32 ipaddr; + unsigned long num; +} ipchildren; + +connections *children; +ipchildren *numipchildren; + int flag1 = 0; unsigned long backlog = 20; unsigned long uid = 0; @@ -278,6 +320,7 @@ { int wstat; int pid; + int i; while ((pid = wait_nohang(&wstat)) > 0) { if (verbosity >= 2) { @@ -286,6 +329,12 @@ strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0); } if (numchildren) --numchildren; printstatus(); + for (i=0;ifd = -1; + + if (!periplimit) + periplimit = limit; + if (limit= limit) sig_pause(); sig_unblock(sig_child); @@ -403,9 +504,43 @@ sig_block(sig_child); if (t == -1) continue; + + for (i=0;iipaddr || !ipcount->num) + lastempty = i; + else if (ipcount->ipaddr == ipaddr) { + ++ipcount->num; + break; + } + } + if (i == limit) { + if (lastempty) { + i = lastempty; + ipcount = &numipchildren[i]; + ipcount->ipaddr = ipaddr; + ipcount->num = 1; + } else + /* never reached */ + strerr_die2x(111,DROP,"internal problem"); + } + if (ipcount->num > periplimit) { + remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0; + strerr_warn3(DROP, "per ip limit reached for ", remoteipstr, 0); + close(t); + --ipcount->num; + continue; + } ++numchildren; printstatus(); - switch(fork()) { + switch(pid = fork()) { case 0: close(s); doit(t); @@ -415,12 +550,148 @@ sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); +#ifdef WITH_SSL + if (flagssl == 1) { + if (pipe(pi2c) != 0) + strerr_die2sys(111,DROP,"unable to create pipe: "); + if (pipe(pi4c) != 0) + strerr_die2sys(111,DROP,"unable to create pipe: "); + switch(fork()) { + case 0: + close(0); close(1); + close(pi2c[1]); + close(pi4c[0]); + if ((fd_move(0,pi2c[0]) == -1) || (fd_move(1,pi4c[1]) == -1)) + strerr_die2sys(111,DROP,"unable to set up descriptors: "); + /* signals are allready set in the parent */ + pathexec(argv); + strerr_die4sys(111,DROP,"unable to run ",*argv,": "); + case -1: + strerr_die2sys(111,DROP,"unable to fork: "); + default: + ssl = SSL_new(ctx); + if (!ssl) + strerr_die2x(111,DROP,"unable to set up SSL session"); + sbio = BIO_new_socket(0,BIO_NOCLOSE); + if (!sbio) + strerr_die2x(111,DROP,"unable to set up BIO socket"); + SSL_set_bio(ssl,sbio,sbio); + close(pi2c[0]); + close(pi4c[1]); + translate(ssl, pi2c[1], pi4c[0], 3600); + _exit(0); + } + } +#endif pathexec(argv); strerr_die4sys(111,DROP,"unable to run ",*argv,": "); case -1: strerr_warn2(DROP,"unable to fork: ",&strerr_sys); --numchildren; printstatus(); + break; + default: + children[freechild].pid = pid; + children[freechild].offset = i; } close(t); } } + +#ifdef WITH_SSL +static int allwrite(int fd, char *buf, int len) +{ + int w; + + while (len) { + w = write(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +static int allwritessl(SSL* ssl, char *buf, int len) +{ + int w; + + while (len) { + w = SSL_write(ssl,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +char tbuf[2048]; + +void translate(SSL* ssl, int clearout, int clearin, unsigned int iotimeout) +{ + struct taia now; + struct taia deadline; + iopause_fd iop[2]; + int flagexitasap; + int iopl; + int sslout, sslin; + int n, r; + + sslin = SSL_get_fd(ssl); + sslout = SSL_get_fd(ssl); + if (sslin == -1 || sslout == -1) + strerr_die2x(111,DROP,"unable to set up SSL connection"); + + flagexitasap = 0; + + if (SSL_accept(ssl)<=0) + strerr_die2x(111,DROP,"unable to accept SSL connection"); + + while (!flagexitasap) { + taia_now(&now); + taia_uint(&deadline,iotimeout); + taia_add(&deadline,&now,&deadline); + + /* fill iopause struct */ + iopl = 2; + iop[0].fd = sslin; + iop[0].events = IOPAUSE_READ; + iop[1].fd = clearin; + iop[1].events = IOPAUSE_READ; + + /* do iopause read */ + iopause(iop,iopl,&deadline,&now); + if (iop[0].revents) { + /* data on sslin */ + n = SSL_read(ssl, tbuf, sizeof(tbuf)); + if ( n < 0 ) + strerr_die2sys(111,DROP,"unable to read form network: "); + if ( n == 0 ) + flagexitasap = 1; + r = allwrite(clearout, tbuf, n); + if ( r < 0 ) + strerr_die2sys(111,DROP,"unable to write to client: "); + } + if (iop[1].revents) { + /* data on clearin */ + n = read(clearin, tbuf, sizeof(tbuf)); + if ( n < 0 ) + strerr_die2sys(111,DROP,"unable to read form client: "); + if ( n == 0 ) + flagexitasap = 1; + r = allwritessl(ssl, tbuf, n); + if ( r < 0 ) + strerr_die2sys(111,DROP,"unable to write to network: "); + } + if (!iop[0].revents && !iop[1].revents) + strerr_die2x(0, DROP,"timeout reached without input"); + } +} +#endif