diff -P -C 5 ucspi-tcp-0.88/Makefile ucspi-tcp-0.88-sql/Makefile
*** ucspi-tcp-0.88/Makefile	Sat Dec 29 21:54:47 2007
--- ucspi-tcp-0.88-sql/Makefile	Sat Dec 29 21:50:55 2007
***************
*** 564,573 ****
--- 564,577 ----
  rules.o: \
  compile rules.c alloc.h stralloc.h gen_alloc.h open.h cdb.h uint32.h \
  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
  
  seek_set.o: \
***************
*** 813,836 ****
  compile tcprulescheck.c byte.h buffer.h strerr.h env.h rules.h \
  stralloc.h gen_alloc.h
  	./compile tcprulescheck.c
  
  tcpserver: \
! 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  $(LIBS) `cat socket.lib`
  
  tcpserver.0: \
  tcpserver.1
  	nroff -man tcpserver.1 > tcpserver.0
  
  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 \
  stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \
  taia.h
  	./compile $(DEFINES) $(INCS) tcpserver.c
  
  time.a: \
--- 817,840 ----
  compile tcprulescheck.c byte.h buffer.h strerr.h env.h rules.h \
  stralloc.h gen_alloc.h
  	./compile tcprulescheck.c
  
  tcpserver: \
! 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 db.o remoteinfo.o timeoutconn.o cdb.a \
  	dns.a time.a unix.a byte.a  $(LIBS) `cat socket.lib`
  
  tcpserver.0: \
  tcpserver.1
  	nroff -man tcpserver.1 > tcpserver.0
  
  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 db.h \
  stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \
  taia.h
  	./compile $(DEFINES) $(INCS) tcpserver.c
  
  time.a: \
diff -P -C 5 ucspi-tcp-0.88/conf-cc ucspi-tcp-0.88-sql/conf-cc
*** ucspi-tcp-0.88/conf-cc	Sat Mar 18 16:18:42 2000
--- ucspi-tcp-0.88-sql/conf-cc	Sat Dec 29 21:20:12 2007
***************
*** 1,3 ****
! gcc -O2
  
  This will be used to compile .c files.
--- 1,3 ----
! gcc -O2 -I/usr/local/include/mysql
  
  This will be used to compile .c files.
diff -P -C 5 ucspi-tcp-0.88/conf-ld ucspi-tcp-0.88-sql/conf-ld
*** ucspi-tcp-0.88/conf-ld	Sat Mar 18 16:18:42 2000
--- ucspi-tcp-0.88-sql/conf-ld	Sat Dec 29 21:20:12 2007
***************
*** 1,3 ****
! gcc -s
  
  This will be used to link .o files into an executable.
--- 1,3 ----
! gcc -s  -I/usr/local/include/mysql -L /usr/local/lib/mysql -l mysqlclient
  
  This will be used to link .o files into an executable.
diff -P -C 5 ucspi-tcp-0.88/db.c ucspi-tcp-0.88-sql/db.c
*** ucspi-tcp-0.88/db.c	Thu Jan  1 01:00:00 1970
--- ucspi-tcp-0.88-sql/db.c	Sat Dec 29 21:20:12 2007
***************
*** 0 ****
--- 1,190 ----
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <strings.h>
+ #include <mysql.h>
+ #include "db.h"
+ 
+ /*
+ server  sql.mailserver.com
+ port    3306
+ database        vpopmail
+ table   relay
+ user    vpopmail
+ pass    secret
+ time    1800
+ denytable deny_from
+ denytime  24
+ */
+ #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;
+ char db_denytable[256];
+ int  deny_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;
+    }
+ 
+    mysql_options( dbh, MYSQL_READ_DEFAULT_GROUP, "vpopmail" );
+    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;
+ }
+ 
+ /*
+  * check is must deny the remote ip address
+  * -> returns -1 is db error (should be denied for safety)
+  *             0 if not denied
+  *             1 if denied
+  */
+ int check_deny(char *remoteip) {
+    char query[MAX_QUERY_STRING];
+    int num_rows = 0;
+    int ret = -1;
+    MYSQL_RES *res;
+ 
+ 	/* deny_from timeout is 60x3600x24 = 5184000 sec. */
+    snprintf(query,MAX_QUERY_STRING,"SELECT timestamp FROM %s WHERE '%s' LIKE CONCAT(ip_addr,'%%') AND (timestamp>(UNIX_TIMESTAMP()-%d) OR timestamp IS NULL )", db_denytable, remoteip, deny_timeout*216000);
+ 
+    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 || getenv( "UCSPI_DEBUG" )) {
+       fprintf(stderr,"QUERY(err:%d/rows:%d): %s\n",ret,num_rows,query); /* */
+    }
+ 
+    if(num_rows>0) {
+      return 1;
+    } else {
+      return 0;
+    }
+ }
+ 
+ /*
+  * check if remote ip address is in vrelay table
+  * ->returns -1 for db error (should not allow relay for safety)
+  *            0 is ip is recorded and ok
+  *            1 if ip is unknow (or timeout is expired)
+  */
+ int check_db(char *remoteip) {
+    char query[MAX_QUERY_STRING];
+    int num_rows = 0;
+    int ret = -1;
+    MYSQL_RES *res;
+ 
+    if( getenv( "UCSPI_DEBUG" )) fprintf( stderr, "remoteip=%s\n", remoteip );
+    snprintf(query,MAX_QUERY_STRING,"SELECT timestamp FROM %s WHERE '%s' LIKE CONCAT(ip_addr,'%%') AND (timestamp>(UNIX_TIMESTAMP()-%d) OR timestamp IS NULL )", 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 || getenv( "UCSPI_DEBUG" )) {
+       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 -P -C 5 ucspi-tcp-0.88/db.h ucspi-tcp-0.88-sql/db.h
*** ucspi-tcp-0.88/db.h	Thu Jan  1 01:00:00 1970
--- ucspi-tcp-0.88-sql/db.h	Sat Dec 29 21:20:12 2007
***************
*** 0 ****
--- 1,20 ----
+ #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;
+ extern char db_denytable[256];
+ extern int  deny_timeout;
+ 
+ int open_db(char *database, char *host, int port, char *username, char *password);
+ int check_deny(char *remoteip);
+ int check_db(char *remoteip);
+ void db_ping();
+ void db_close();
+ 
+ #endif
diff -P -C 5 ucspi-tcp-0.88/tcpserver.c ucspi-tcp-0.88-sql/tcpserver.c
*** ucspi-tcp-0.88/tcpserver.c	Sat Dec 29 21:54:47 2007
--- ucspi-tcp-0.88-sql/tcpserver.c	Sat Dec 29 21:48:24 2007
***************
*** 1,9 ****
--- 1,14 ----
+ #include <errno.h>
+ #include <stdio.h>
  #include <sys/types.h>
  #include <sys/param.h>
  #include <netdb.h>
+ #include <string.h>
+ #include <stdlib.h>
  #include <openssl/ssl.h>
+ 
  #include "uint16.h"
  #include "str.h"
  #include "byte.h"
  #include "fmt.h"
  #include "scan.h"
***************
*** 24,39 ****
--- 29,46 ----
  #include "pathexec.h"
  #include "socket.h"
  #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;
  int flagparanoid = 0;
  unsigned long timeout = 26;
***************
*** 76,85 ****
--- 83,93 ----
  /* ---------------------------- child */
  
  #define DROP "tcpserver: warning: dropping connection, "
  
  int flagdeny = 0;
+ int flagrelay = 0;
  int flagallownorules = 0;
  char *fnrules = 0;
  
  void drop_nomem(void)
  {
***************
*** 115,124 ****
--- 123,136 ----
  }
  void drop_rules(void)
  {
    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)
  {
    unsigned int next0;
    unsigned int split;
***************
*** 207,218 ****
        flagremoteinfo = 0;
      if (!stralloc_0(&tcpremoteinfo)) drop_nomem();
    }
    env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
  
!   if (fnrules) {
      int fdrules;
      fdrules = open_read(fnrules);
      if (fdrules == -1) {
        if (errno != error_noent) drop_rules();
        if (!flagallownorules) drop_rules();
      }
--- 219,233 ----
        flagremoteinfo = 0;
      if (!stralloc_0(&tcpremoteinfo)) drop_nomem();
    }
    env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
  
!   if(usemysql && flagrelay ) env("RELAYCLIENT","");
! 
!   if(fnrules) {
      int fdrules;
+ 
      fdrules = open_read(fnrules);
      if (fdrules == -1) {
        if (errno != error_noent) drop_rules();
        if (!flagallownorules) drop_rules();
      }
***************
*** 250,279 ****
  void usage(void)
  {
  #ifndef WITH_SSL
    strerr_warn1("\
  tcpserver: usage: tcpserver \
! [ -1UXpPhHrRoOdDqQv ] \
  [ -c limit ] \
  [ -C [address[/len]:]limit ] \
  [ -e name=var ] \
! [ -x rules.cdb ] \
  [ -B banner ] \
  [ -g gid ] \
  [ -u uid ] \
  [ -b backlog ] \
  [ -l localname ] \
  [ -t timeout ] \
  host port program",0);
  #else
    strerr_warn1("\
  tcpserver: usage: tcpserver \
! [ -1UXpPhHrRoOdDqQsSv ] \
  [ -c limit ] \
  [ -C [address[/len]:]limit ] \
  [ -e name=var ] \
! [ -x rules.cdb ] \
  [ -B banner ] \
  [ -g gid ] \
  [ -u uid ] \
  [ -b backlog ] \
  [ -l localname ] \
--- 265,294 ----
  void usage(void)
  {
  #ifndef WITH_SSL
    strerr_warn1("\
  tcpserver: usage: tcpserver \
! [ -1UXpPhHrRoOdDqQv ] \
  [ -c limit ] \
  [ -C [address[/len]:]limit ] \
  [ -e name=var ] \
! [ -x rules.cdb  | -M sql.conf ] \
  [ -B banner ] \
  [ -g gid ] \
  [ -u uid ] \
  [ -b backlog ] \
  [ -l localname ] \
  [ -t timeout ] \
  host port program",0);
  #else
    strerr_warn1("\
  tcpserver: usage: tcpserver \
! [ -1UXpPhHrRoOdDqQsSv ] \
  [ -c limit ] \
  [ -C [address[/len]:]limit ] \
  [ -e name=var ] \
! [ -x rules.cdb  | -M sql.conf ] \
  [ -B banner ] \
  [ -g gid ] \
  [ -u uid ] \
  [ -b backlog ] \
  [ -l localname ] \
***************
*** 424,433 ****
--- 439,449 ----
    char *iplimenv;
    int flagiplim;
    unsigned long u;
    int s;
    int t;
+   char sqlconf[1024];
    unsigned int i;
    int pid;
  #ifdef WITH_SSL
    BIO *sbio;
    SSL *ssl;
***************
*** 436,448 ****
  
    ctx = NULL;
  
    if (!stralloc_copys(&certfile, CERTFILE) || !stralloc_0(&certfile) )
      strerr_die2x(111,FATAL,"out of memory");
!   while ((opt = getopt(argc,argv,"dDvqQhHrRsS1UXx:t:u:g:l:b:B:c:C:e:n:pPoO")) != opteof)
  #else
!   while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:C:e:pPoO")) != opteof)
  #endif
      switch(opt) {
        case 'b': scan_ulong(optarg,&backlog); break;
        case 'c': scan_ulong(optarg,&limit); break;
        case 'C': ip_limit_add(optarg); break;
--- 452,464 ----
  
    ctx = NULL;
  
    if (!stralloc_copys(&certfile, CERTFILE) || !stralloc_0(&certfile) )
      strerr_die2x(111,FATAL,"out of memory");
!   while ((opt = getopt(argc,argv,"dDvqQhHrRsS1UXM:x:t:u:g:l:b:B:c:C:e:n:pPoO")) != opteof)
  #else
!   while ((opt = getopt(argc,argv,"dDvqQhHrR1UXM:x:t:u:g:l:b:B:c:C:e:pPoO")) != opteof)
  #endif
      switch(opt) {
        case 'b': scan_ulong(optarg,&backlog); break;
        case 'c': scan_ulong(optarg,&limit); break;
        case 'C': ip_limit_add(optarg); break;
***************
*** 479,488 ****
--- 495,509 ----
        case 'n': if (!stralloc_copys(&certfile, optarg) ||
  		    !stralloc_0(&certfile) )
  		  strerr_die2x(111,FATAL,"out of memory");
  		break;
  #endif
+       case 'M': usemysql = 1;
+          strcpy( sqlconf, optarg );
+          if( getenv( "UCSPI_DEBUG" )) fprintf( stderr, "sqlconf set to %s\n", sqlconf );
+          break;
+ 
        default: usage();
      }
    argc -= optind;
    argv += optind;
  
***************
*** 578,593 ****
--- 599,703 ----
    printstatus();
   
    for (;;) {
      while (numchildren >= limit) sig_pause();
  
+     flagdeny=0;
+     flagrelay=0;
      sig_unblock(sig_child);
      t = socket_accept4(s,remoteip,&remoteport);
      sig_block(sig_child);
  
      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(sqlconf,"r")) {
+              if( getenv( "UCSPI_DEBUG" )) fprintf( stderr, "fopen ok\n" );
+              char line[256];
+              char tag[256];
+              char value[256];
+ 
+              while(fgets(line,256,fp)) {
+                /* if( getenv( "UCSPI_DEBUG" )) fprintf( stderr, "read line '%s'\n", line ); */
+                char *comment;
+ 
+                if(comment=strchr(line,'#')) {
+                   *comment='\0';
+                }
+                /* if(sscanf(line,"%s\t%s\n", tag, value) != 2) continue; */
+                if(sscanf(line,"%s %s\n", tag, value) != 2) continue;
+                /* fprintf(stderr,"Warning: got Line: [%s]\n",line); */
+                if( getenv( "UCSPI_DEBUG" )) fprintf( stderr, "tag='%s', value='%s'\n", tag, value );
+ 
+                /*
+                  server    sql.domain.com
+                  port      3306
+                  database  vpopmail
+                  table     relay
+                  user      vpopmail
+                  pass      secret
+                  time      1800
+                  denytable deny_from
+                  denytime  24 (h)
+                */
+                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 if(!strcasecmp(tag,"denytable")) {
+                         strcpy(db_denytable,value);
+                } else if(!strcasecmp(tag,"denytime")) {
+                         deny_timeout=atoi(value);
+                } else {
+                fprintf(stderr,"Warning: Bad sql: TAG: [%s] VALUE: [%s]\n",tag,value);
+                }
+              }
+          } else {
+            fprintf( stderr, "unable to open %s file: %s\n", sqlconf, strerror( errno ));
+          }
+          if(db_port==-1) {
+            fprintf(stderr,"Error: Failed to read %s\n", sqlconf);
+            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();
+          ret=check_deny(remoteipstr);
+          if( getenv( "UCSPI_DEBUG" )) fprintf( stderr, "check_deny returns %d (%s)\n", ret, ret<0 ? "db_error" : ( ret>0 ? "denied" : "allowed" ));
+          if( ret != 0 )
+             flagdeny = 1;
+          else {
+            ret=check_db(remoteipstr);
+            if( getenv( "UCSPI_DEBUG" )) fprintf( stderr, "check_db returns %d (%s)\n", ret, ret<0 ? "db_error" : ( ret>0 ? "no_relay_allowed" : "relay_allowed" ));
+            if( ret < 0 ) flagdeny = 1;
+            if( ret == 0 ) flagrelay = 1;
+          }
+       }
+     }
  
      /* per ip handling */
      flagiplim = 0;
      if (ip_limit_check(remoteip, 1)) {
        remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
