Download | Plain Text | Line Numbers


--- FILES	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ FILES	5 Apr 2004 15:34:57 -0000	1.2
@@ -216,6 +216,7 @@
 warn-auto.sh
 warn-shsgr
 x86cpuid.c
+fixcrio.1
 dns_ip6.c
 dns_ipq6.c
 dns_nd6.c
--- Makefile	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ Makefile	5 Apr 2004 15:34:57 -0000	1.3
@@ -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/local/include
+OPENSSLBIN=openssl
+
 SHELL=/bin/sh
 
 default: it
@@ -755,7 +763,7 @@
 load tcpserver.o rules.o remoteinfo6.o timeoutconn6.o cdb.a dns.a \
 time.a unix.a byte.a socket.lib
 	./load tcpserver rules.o remoteinfo6.o timeoutconn6.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 \
@@ -764,7 +772,7 @@
 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 uint32.h
-	./compile tcpserver.c
+	./compile $(DEFINES) $(INCS) tcpserver.c
 
 time.a: \
 makelib iopause.o tai_pack.o taia_add.o taia_approx.o taia_frac.o \
@@ -967,3 +975,18 @@
 
 clean:
 	rm -f `cat TARGETS`
+
+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"
+
+
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ fixcrio.1	5 Apr 2004 15:34:57 -0000	1.1
@@ -0,0 +1,15 @@
+.TH fixcrio 1
+.SH NAME
+fixcrio \- make sure that there is a CR before each LF
+.SH SYNOPSIS
+.B fixcrio
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B fixcrio
+inserts CR at the end of each line of input where a CR is not already present.
+It does not insert CR at the end of a partial final line.
+.SH "SEE ALSO"
+addcr(1)
--- hier.c	14 Jun 2002 08:47:32 -0000	1.1.1.1
+++ hier.c	5 Apr 2004 15:34:57 -0000	1.2
@@ -26,6 +26,7 @@
   c(auto_home,"bin","fixcrio",-1,-1,0755);
   c(auto_home,"bin","rblsmtpd",-1,-1,0755);
 
+  c(auto_home,"man/man1","fixcrio.1",-1,-1,0644);
   c(auto_home,"man/man1","tcpclient.1",-1,-1,0644);
   c(auto_home,"man/man1","tcpserver.1",-1,-1,0644);
   c(auto_home,"man/man1","tcprules.1",-1,-1,0644);
 }
--- tcprules.c	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ tcprules.c	16 Mar 2004 15:12:26 -0000	1.2
@@ -94,6 +94,7 @@
   int len;
   int fd;
   int i;
+  int e;
   char ch;
 
   fn = argv[1];
@@ -154,8 +155,16 @@
     while (len)
       switch(*x) {
         case ',':
+	  e = byte_chr(x + 1,len - 1,',');
           i = byte_chr(x,len,'=');
-          if (i == len) die_bad();
+          if (i > e) {
+	    if (e < 2 || x[1] != '!') die_bad();
+	    if (!stralloc_catb(&data,"-",1)) nomem();
+	    if (!stralloc_catb(&data,x + 2,e - 1)) nomem();
+	    if (!stralloc_0(&data)) nomem();
+	    x += e + 1; len -= e + 1;
+	    break;
+	  }
           if (!stralloc_catb(&data,"+",1)) nomem();
           if (!stralloc_catb(&data,x + 1,i)) nomem();
           x += i + 1; len -= i + 1;
--- tcprulescheck.c	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ tcprulescheck.c	16 Mar 2004 15:12:27 -0000	1.2
@@ -22,6 +22,11 @@
 	buffer_puts(buffer_1,data + 1);
 	buffer_puts(buffer_1,"\n");
 	break;
+      case '-':
+	buffer_puts(buffer_1,"unset environment variable ");
+	buffer_puts(buffer_1,data + 1);
+	buffer_puts(buffer_1,"\n");
+	break;
     }
     ++next0;
     data += next0; datalen -= next0;
--- tcpserver.1.orig	1 Jan 1970 00:00:00 -0000
+++ tcpserver.1	6 Apr 2004 11:49:45 -0000	1.2
@@ -4,7 +4,7 @@
 .SH SYNOPSIS
 .B tcpserver
 [
-.B \-146jpPhHrRoOdDqQv
+.B \-146UXpPhHrRoOdDqQsSv
 ]
 [
 .B \-c\fIlimit
@@ -31,6 +31,9 @@
 .B \-t\fItimeout
 ]
 [
+.B \-n\fIcertfile
+]
+[
 .B \-I\fIinterface
 ]
 .I host
@@ -204,11 +207,31 @@
 (Default.)
 Print error messages.
 .TP
+.B \-s
+Enable SSL/TLS mode. This modus needs a SSL enabled build and a certificat.
+.TP
+.B \-S
+(Default.)
+Don't enable SSL/TLS mode.
+.TP
+.B \-n\fIcertfile
+Instead of the default ./cert.pem certificate us the specified
+.IR certfile .
+.TP
 .B \-v
 Verbose.
 Print all available messages.
 .SH "DATA-GATHERING OPTIONS"
 .TP
+.B \-X
+With
+.BR -x\fIcdb ,
+allow connections even if
+.I cdb
+does not exist.
+Normally the connection gets dropped.
+.SH "DATA-GATHERING OPTIONS"
+.TP
 .B \-p
 Paranoid.
 After looking up the remote host name,
@@ -256,6 +279,13 @@
 after
 .I timeout
 seconds. Default: 26.
+.SH ENVIRONMENT
+.TP
+.B SSL_CIPHER
+Specifies the ciphers that should be used in SSL/TLS mode.
+See
+.I openssl(1)
+for more information.
 .SH "SEE ALSO"
 argv0(1),
 fixcr(1),
@@ -264,3 +294,4 @@
 tcprules(1),
 listen(2),
 tcp-environ(5)
+openssl(1)
--- tcpserver.c	14 Jun 2002 08:47:30 -0000	1.1.1.1
+++ tcpserver.c	1 Apr 2005 15:13:15 -0000	1.8
@@ -1,6 +1,8 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <netdb.h>
+#include <openssl/ssl.h>
+#include <fcntl.h>
 #include "uint16.h"
 #include "str.h"
 #include "byte.h"
@@ -39,6 +40,13 @@
 int flagparanoid = 0;
 unsigned long timeout = 26;
 uint32 netif = 0;
+#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;
 
@@ -130,6 +138,9 @@
 	  env(data + 1,data + 1 + split + 1);
 	}
 	break;
+      case '-':
+	env(data + 1, (char *)0);
+	break;
     }
     ++next0;
     data += next0; datalen -= next0;
@@ -271,6 +282,7 @@
 
 void usage(void)
 {
+#ifndef WITH_SSL
   strerr_warn1("\
 tcpserver: usage: tcpserver \
 [ -461UXpPhHrRoOdDqQv ] \
@@ -282,8 +294,23 @@
 [ -b backlog ] \
 [ -l localname ] \
 [ -t timeout ] \
+host port program",0);
+#else
+  strerr_warn1("\
+tcpserver: usage: tcpserver \
+[ -461UXpPhHrRoOdDqQsSv ] \
+[ -c limit ] \
+[ -x rules.cdb ] \
+[ -B banner ] \
+[ -g gid ] \
+[ -u uid ] \
+[ -b backlog ] \
+[ -l localname ] \
+[ -t timeout ] \
+[ -n certfile ] \
 [ -I interface ] \
 host port program",0);
+#endif
   _exit(100);
 }
 
@@ -334,7 +361,20 @@
   int s;
   int t;
 
+#ifdef WITH_SSL
+  BIO *sbio;
+  SSL *ssl;
+  SSL_CTX *ctx;
+  int pi2c[2], pi4c[2];
+
+  ctx = NULL;
+
+  if (!stralloc_copys(&certfile, CERTFILE) || !stralloc_0(&certfile) )
+    strerr_die2x(111,FATAL,"out of memory");
+  while ((opt = getopt(argc,argv,"46dDvqQhHrRsS1UXx:t:u:g:l:b:B:c:n:I:pPoO")) != opteof)
+#else
   while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof)
+#endif
     switch(opt) {
       case 'b': scan_ulong(optarg,&backlog); break;
       case 'c': scan_ulong(optarg,&limit); break;
@@ -364,6 +404,14 @@
       case '4': noipv6 = 1; break;
       case '6': forcev6 = 1; break;
       case 'l': localhost = optarg; break;
+#ifdef WITH_SSL
+      case 's': flagssl = 1; break;
+      case 'S': flagssl = 0; break;
+      case 'n': if (!stralloc_copys(&certfile, optarg) ||
+		    !stralloc_0(&certfile) )
+		  strerr_die2x(111,FATAL,"out of memory");
+		break;
+#endif
       default: usage();
     }
   argc -= optind;
@@ -371,6 +419,11 @@
 
   if (!verbosity)
     buffer_2->fd = -1;
+
+  if (limit == 0)
+    strerr_die2x(100,FATAL,"limit may not be set to 0");
+  if (limit > 65000)
+    strerr_die2x(100,FATAL,"limit way to high");
 
   hostname = *argv++;
   if (!hostname) usage();
@@ -412,6 +465,25 @@
       noipv6=1;
   }
 
+#ifdef WITH_SSL
+  if (flagssl == 1) {
+    /* setup SSL context (load key and cert into ctx) */
+    SSL_library_init();
+    ctx=SSL_CTX_new(SSLv23_server_method());
+    if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context");
+
+    /* set prefered ciphers */
+    if (env_get("SSL_CIPHER"))
+      if (SSL_CTX_set_cipher_list(ctx, env_get("SSL_CIPHER")) == 0)
+	strerr_die2x(111,FATAL,"unable to set cipher list");
+
+    if(SSL_CTX_use_RSAPrivateKey_file(ctx, certfile.s, SSL_FILETYPE_PEM) != 1)
+      strerr_die2x(111,FATAL,"unable to load RSA private key");
+    if(SSL_CTX_use_certificate_chain_file(ctx, certfile.s) != 1)
+      strerr_die2x(111,FATAL,"unable to load certificate");
+  }
+#endif
+  
   s = socket_tcp6();
   if (s == -1)
     strerr_die2sys(111,FATAL,"unable to create socket: ");
@@ -461,6 +533,39 @@
         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:
@@ -470,3 +575,186 @@
     close(t);
   }
 }
+
+#ifdef WITH_SSL
+int ssl_timeoutio(int (*func)(), long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
+{
+  int n;
+  const long end = t + time(NULL);
+
+  do {
+    fd_set fds;
+    struct timeval tv;
+
+    const int r = buf ? func(ssl, buf, len) : func(ssl);
+    if (r > 0)
+      return r;
+
+    t = end - time(NULL);
+    if (t < 0)
+      break;
+    tv.tv_sec = t;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&fds);
+    switch (SSL_get_error(ssl, r))
+    {
+    default:
+      return r; /* some other error */
+    case SSL_ERROR_WANT_READ:
+      FD_SET(rfd, &fds);
+      n = select(rfd + 1, &fds, NULL, NULL, &tv);
+      break;
+    case SSL_ERROR_WANT_WRITE:
+      FD_SET(wfd, &fds);
+      n = select(wfd + 1, NULL, &fds, NULL, &tv);
+      break;
+    }
+
+    /* n is the number of descriptors that changed status */
+  }
+  while (n > 0);
+
+  if (n != -1) errno = error_timeout;
+  return -1;
+}
+
+int ssl_timeoutaccept(long t, int rfd, int wfd, SSL *ssl)
+{
+  int r;
+
+  /* if connection is established, keep NDELAY */
+  if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1)
+    return -1;
+  r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0);
+
+  if (r <= 0) {
+    ndelay_off(rfd);
+    ndelay_off(wfd);
+  }
+  else
+    SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+  return r;
+}
+
+int ssl_timeoutread(long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
+{
+  if (!buf)
+    return 0;
+  if (SSL_pending(ssl))
+    return SSL_read(ssl, buf, len);
+  return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len);
+}
+
+int ssl_timeoutwrite(long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
+{
+  if (!buf)
+    return 0;
+  return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len);
+}
+
+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(long t, int rfd, int wfd, SSL* ssl, char *buf, int len)
+{
+  int w;
+
+  while (len) {
+    w = ssl_timeoutwrite(t, rfd, wfd, 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_timeoutaccept(timeout, sslin, sslout, 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) {
+      do {
+        /* data on sslin */
+        n = ssl_timeoutread(iotimeout, sslin, sslout, 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 the data payload was longer than sizeof(tbuf) then SSL will have
+	 * bytes processed and pending. We need to pick them up and write them
+	 * to clearout.
+	 */
+      } while (SSL_pending(ssl));
+    }
+    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(iotimeout, sslin, sslout, 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