diff -urN ss5-3.8.9/include/SS5Main.h ss5-3.8.9.patched/include/SS5Main.h
--- ss5-3.8.9/include/SS5Main.h	2012-01-11 13:22:42.000000000 +0100
+++ ss5-3.8.9.patched/include/SS5Main.h	2013-05-04 11:06:42.830511065 +0200
@@ -302,6 +302,7 @@
   int  Socket;
   int  appSocket;
   char SrcAddr[16];
+  char SrvAddr[INET_ADDRSTRLEN];
   UINT SrcPort;
   UINT GssEnc;
 
diff -urN ss5-3.8.9/include/SS5Mod_authentication.h ss5-3.8.9.patched/include/SS5Mod_authentication.h
--- ss5-3.8.9/include/SS5Mod_authentication.h	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/include/SS5Mod_authentication.h	2013-05-04 14:31:09.708040590 +0200
@@ -96,5 +96,10 @@
 			 struct _S5AuthCacheNode *node
 );
 
+void
+  DropAuthCache(	char *u,
+			char *p
+);
+
 
 #endif
diff -urN ss5-3.8.9/include/SS5NVPNAuthPool.h ss5-3.8.9.patched/include/SS5NVPNAuthPool.h
--- ss5-3.8.9/include/SS5NVPNAuthPool.h	1970-01-01 01:00:00.000000000 +0100
+++ ss5-3.8.9.patched/include/SS5NVPNAuthPool.h	2013-05-06 12:22:15.324427330 +0200
@@ -0,0 +1,30 @@
+
+
+#ifndef SS5NVPNAUTHPOOL_H
+#define SS5NVPNAUTHPOOL_H 1
+
+struct popenfd
+{
+   int pin;
+   int pout;
+   pid_t handler;
+   char locked;
+};
+
+#define ISTREAM 0
+#define OSTREAM 1
+
+#define AUTH_WORKERS 20
+#define SUCCESS_RESPONSE "OK\n"
+
+void dump_popenfd(struct popenfd *psfd);
+void send_auth(struct popenfd *psfd, char* username, char* password, char* ipaddr);
+int read_auth(struct popenfd *psfd);
+void popen2(char* command, struct popenfd *psfd);
+void pclose2(struct popenfd *psfd);
+struct popenfd * get_free_ps();
+void release_ps(struct popenfd *ps);
+int authorize(char* username, char* password, char* ipaddr);
+void init_auth(char* worker_path);
+
+#endif
diff -urN ss5-3.8.9/include/SS5Server.h ss5-3.8.9.patched/include/SS5Server.h
--- ss5-3.8.9/include/SS5Server.h	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/include/SS5Server.h	2013-05-04 20:23:43.088895215 +0200
@@ -64,5 +64,15 @@
                         pid_t pid
 );
 
+void
+  NVPNSetBoundAddress(	char *addr,
+			UINT sockfd
+);
+
+void
+  NVPNBindAppSocket(	char *addr,
+			UINT sockfd
+);
+
 
 #endif
diff -urN ss5-3.8.9/modules/mod_authen/Makefile.in ss5-3.8.9.patched/modules/mod_authen/Makefile.in
--- ss5-3.8.9/modules/mod_authen/Makefile.in	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/modules/mod_authen/Makefile.in	2013-05-06 12:28:07.114008635 +0200
@@ -2,6 +2,7 @@
 MODULE	    =	mod_authentication.so
 
 MODULEOBJ  = 	SS5Mod_authentication.o		\
+		SS5NVPNAuthPool.o		\
 		SS5Basic.o			\
 		SS5ExternalProgram.o		\
 		SS5Pam.o			\
diff -urN ss5-3.8.9/modules/mod_authen/SS5ExternalProgram.c ss5-3.8.9.patched/modules/mod_authen/SS5ExternalProgram.c
--- ss5-3.8.9/modules/mod_authen/SS5ExternalProgram.c	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/modules/mod_authen/SS5ExternalProgram.c	2013-05-06 13:04:08.163807709 +0200
@@ -20,6 +20,31 @@
 #include "SS5Main.h"
 #include "SS5Mod_authentication.h"
 #include "SS5ExternalProgram.h"
+#include "SS5NVPNAuthPool.h"
+
+/* Converts an integer value to its hex character*/
+char to_hex(char code) {
+  static char hex[] = "0123456789abcdef";
+  return hex[code & 15];
+}
+
+/* Returns a url-encoded version of str */
+/* IMPORTANT: be sure to free() the returned string after use */
+char *url_encode(char *str) {
+  char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
+  while (*pstr) {
+    if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
+      *pbuf++ = *pstr;
+    else if (*pstr == ' ')
+      *pbuf++ = '+';
+    else
+      *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
+    pstr++;
+  }
+  *pbuf = '\0';
+  return buf;
+}
+
 
 UINT S5AuthProgramCheck( struct _SS5ClientInfo *ci, pid_t pid )
 {
@@ -27,7 +52,7 @@
   char prog[1024];
 
   char tmp[1024];
-  UINT i,l;
+  UINT status;
 
   char logString[128];
 
@@ -36,62 +61,34 @@
    *    Build command line for program execution escaping each
    *    character not alphanumeric
    */
-  memset(prog, 0, sizeof(prog));
-  memset(tmp, 0, sizeof(tmp));
 
-  strncpy(prog,S5AuthCmd->ProgName,sizeof(S5AuthCmd->ProgName) - 1);
-  STRSCAT(prog," '");
+  //memset(prog, 0, sizeof(prog));
+  //memset(tmp, 0, sizeof(tmp));
 
+  //strncpy(prog,S5AuthCmd->ProgName,sizeof(S5AuthCmd->ProgName) - 1);
+  //STRSCAT(prog," '");
 
-  for (i = 0; ci->Username[i]; i++)
-    {
-      if ( (ci->Username[i] >=48 && ci->Username[i] <=57) || (ci->Username[i] >=65 && ci->Username[i] <=90) || (ci->Username[i] >=97 && ci->Username[i] <=122) )
-	tmp[i] = ci->Username[i];
-      else
-	{
-	  tmp[i] = '\\';
-	  tmp[i + 1] = ci->Username[i];
-	}
-    }
-
-  STRSCAT(prog,tmp);
-  STRSCAT(prog,"' '");
-  memset(tmp, 0, sizeof(tmp)); /* must be reset to null */
-
-  for (i = 0; ci->Password[i]; i++)
-    {
-      if ( (ci->Password[i] >=48 && ci->Password[i] <=57) || (ci->Password[i] >=65 && ci->Password[i] <=90) || (ci->Password[i] >=97 && ci->Password[i] <=122) )
-	tmp[i] = ci->Password[i];
-      else
-	{
-	  tmp[i] = '\\';
-	  tmp[i + 1] = ci->Password[i];
-	}
-    }
-  STRSCAT(prog,tmp);
-  STRSCAT(prog,"'");
+  char *username_decoded = url_encode(ci->Username);
+  //STRSCAT(prog,username_decoded);
+  //free(username_decoded);
+  //STRSCAT(prog,"' '");
+
+  char *password_encoded = url_encode(ci->Password);
+  //STRSCAT(prog,password_encoded);
+  //free(password_encoded);
+  //STRSCAT(prog,"' '");
 
-  /* 
-   *    Open pipe and fork 
-   */
-  if( (stream = popen(prog,"r")) == NULL ) {
-    ERRNO(pid)
-    return ERR;
-  }
-  /* 
-   *    Get standard output from generic external authentication program 
-   */
-  fscanf(stream,"%2s",resp);
+  //STRSCAT(prog,ci->SrvAddr);
+  //STRSCAT(prog,"'");
 
-  if( pclose(stream) == -1 ) {
-    ERRNO(pid)
-  }
-  /* 
-   *    If standard output is equal to "OK" then authenticaton will be OK too 
-   */
-  if( STREQ(resp,"OK",sizeof("OK") - 1) )
-    return OK;
+  if (authorize(username_decoded, password_encoded, ci->SrvAddr))
+    status = OK;
   else
-    return ERR;
+    status = ERR;
+
+  free(username_decoded);
+  free(password_encoded);
+
+  return status;
 }
 
diff -urN ss5-3.8.9/modules/mod_authen/SS5Mod_authentication.c ss5-3.8.9.patched/modules/mod_authen/SS5Mod_authentication.c
--- ss5-3.8.9/modules/mod_authen/SS5Mod_authentication.c	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/modules/mod_authen/SS5Mod_authentication.c	2013-05-04 18:43:02.544619117 +0200
@@ -18,6 +18,7 @@
 
 
 #include"SS5Main.h"
+#include"SS5Server.h"
 #include"SS5Mod_authentication.h"
 #include"SS5Mod_log.h"
 #include"SS5Basic.h"
@@ -64,6 +65,9 @@
 
   memset(ci->Username,0,64);
   memset(ci->Password,0,64);
+  memset(ci->SrvAddr,0,16);
+
+  NVPNSetBoundAddress(ci->SrvAddr, ci->Socket);
 
   strncpy(ci->Username,"\"\"",strlen("\"\""));
 
@@ -253,6 +257,14 @@
               err = S5PwdFileCheck(ci);
           break;
         }
+
+	if (!err) {
+	  LOCKMUTEXAEC()
+	  DropAuthCache(ci->Username,ci->Password);
+	  UNLOCKMUTEXAEC()
+	  return ERR;
+	}
+
       }
       else {
         err = OK;
@@ -463,7 +475,32 @@
   return ERR;
 }
 
+void DropAuthCache(char *u, char *p)
+{
+  register UINT index;
+  struct _S5AuthCacheNode *node, *next, *prev;
+
+    index=S5AuthCacheHash( u, p );
+
+    if( S5AuthCacheList[index]!= NULL ) {
+      next = NULL;
+      prev = NULL;
+      node = S5AuthCacheList[index];
+      do {
+        next = node->next;
 
+        if( STREQ(u,node->Usr,sizeof(node->Usr)) && STREQ(p,node->Pwd,sizeof(node->Pwd)) ) {
+	   if (prev != NULL) prev->next = next;
+	   else S5AuthCacheList[index] = NULL;
+	   free(node);
+	   node = next;
+        } else {
+           prev = node;
+           node = node->next;
+	}
+      } while(node != NULL );
+    }
+}
 
 UINT FreeAuthCache( struct _S5AuthCacheNode **node )
 {
diff -urN ss5-3.8.9/modules/mod_authen/SS5NVPNAuthPool.c ss5-3.8.9.patched/modules/mod_authen/SS5NVPNAuthPool.c
--- ss5-3.8.9/modules/mod_authen/SS5NVPNAuthPool.c	1970-01-01 01:00:00.000000000 +0100
+++ ss5-3.8.9.patched/modules/mod_authen/SS5NVPNAuthPool.c	2013-05-06 13:11:51.711059232 +0200
@@ -0,0 +1,146 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include "SS5NVPNAuthPool.h"
+
+sem_t mutex;
+struct popenfd *auth_workers[AUTH_WORKERS];
+
+void init_auth(char* worker_path)
+{
+   sem_init(&mutex, 0, AUTH_WORKERS);
+
+   int i;
+   for (i = 0 ; i < AUTH_WORKERS ; i++)
+   {
+      auth_workers[i] = (struct popenfd *) malloc(sizeof(struct popenfd));
+      memset(auth_workers[i], 0, sizeof(struct popenfd));
+      popen2(worker_path, auth_workers[i]);
+   }
+}
+
+void destroy()
+{
+   sem_destroy(&mutex);
+
+   int i;
+   for (i = 0 ; i < AUTH_WORKERS ; i++)
+   {
+      kill(auth_workers[i]->handler, SIGTERM);
+      pclose2(auth_workers[i]);
+      free(auth_workers[i]);
+   }
+}
+
+void dump_popenfd(struct popenfd *psfd)
+{
+   if (psfd)
+      printf("popenfd: [pin=%d, pout=%d, handler=%d]\n", psfd->pin, psfd->pout, psfd->handler);
+   else
+      printf("popenfd: not set\n");
+}
+
+struct popenfd * get_free_ps()
+{
+   struct popenfd *s;
+
+   sem_wait(&mutex);
+
+   int i;
+   for (i = 0 ; i < AUTH_WORKERS ; i++)
+   {
+      s = auth_workers[i];
+
+      if (s->locked)
+        continue;
+
+      s->locked = 1;
+      return s;
+   }
+
+   return NULL;
+}
+
+void release_ps(struct popenfd *ps)
+{
+   ps->locked = 0;
+   sem_post(&mutex);
+}
+
+void send_auth(struct popenfd *psfd, char* username, char* password, char* ipaddr)
+{
+   int size = strlen(username) + strlen(password) + strlen(ipaddr) + 4;
+   char auth_request[size];
+   memset(auth_request, 0, size);
+   sprintf(auth_request, "%s %s %s\n", username, password, ipaddr);
+   write(psfd->pin, auth_request, size - 1);
+}
+
+int read_auth(struct popenfd *psfd)
+{
+   char auth_response[64];
+   memset(auth_response, 0, sizeof(auth_response));
+   read(psfd->pout, auth_response, sizeof(auth_response) - 1);
+
+   return (!strcmp(auth_response, SUCCESS_RESPONSE));
+}
+
+int authorize(char* username, char* password, char* ipaddr)
+{
+   struct popenfd *aps = get_free_ps();
+   int status = 0;
+
+   if (aps == NULL)
+      return 0;
+
+   send_auth(aps, username, password, ipaddr);
+   dump_popenfd(aps);
+   status = read_auth(aps);
+   release_ps(aps);
+
+   return status;
+}
+
+
+void popen2(char* command, struct popenfd *psfd)
+{
+   int p_stdin_fd[2], p_stdout_fd[2];
+
+   pipe(p_stdin_fd);
+   pipe(p_stdout_fd);
+
+   pid_t pid = fork();
+
+   if (!pid) // forked process
+   {
+      close(p_stdin_fd[OSTREAM]);
+      close(p_stdout_fd[ISTREAM]);
+
+      dup2(p_stdin_fd[ISTREAM], ISTREAM);
+      dup2(p_stdout_fd[OSTREAM], OSTREAM);
+
+      execl(command, NULL);
+   }
+   else if (pid > 0) // parent process
+   {
+      close(p_stdin_fd[ISTREAM]);
+      close(p_stdout_fd[OSTREAM]);
+
+      psfd->pin = p_stdin_fd[OSTREAM];
+      psfd->pout =  p_stdout_fd[ISTREAM];
+      psfd->handler = pid;
+      psfd->locked = 0;
+   }
+}
+
+void pclose2(struct popenfd *psfd)
+{
+   close(psfd->pin);
+   close(psfd->pout);
+}
+
diff -urN ss5-3.8.9/modules/mod_socks5/SS5Mod_socks5.c ss5-3.8.9.patched/modules/mod_socks5/SS5Mod_socks5.c
--- ss5-3.8.9/modules/mod_socks5/SS5Mod_socks5.c	2012-01-11 13:09:35.000000000 +0100
+++ ss5-3.8.9.patched/modules/mod_socks5/SS5Mod_socks5.c	2013-05-04 20:24:31.601220887 +0200
@@ -1196,6 +1196,9 @@
       err=S5REQUEST_ISERROR;
     }
     else { 
+
+      NVPNBindAppSocket(ci->SrvAddr, ci->appSocket);
+
       /*
        * SS5: set bind interface if configured
        */ 
@@ -1630,6 +1633,9 @@
         err=S5REQUEST_ISERROR;
       }
       else {
+
+        NVPNBindAppSocket(ci->SrvAddr, ci->udpSocket);
+
         memset((char *)&serverbind_ssin, 0, sizeof(struct sockaddr_in));
         serverbind_ssin.sin_family      = AF_INET;
         serverbind_ssin.sin_port        = htons(0);
Binary files ss5-3.8.9/modules/mod_socks5/.SS5Mod_socks5.c.swp and ss5-3.8.9.patched/modules/mod_socks5/.SS5Mod_socks5.c.swp differ
diff -urN ss5-3.8.9/src/Makefile.in ss5-3.8.9.patched/src/Makefile.in
--- ss5-3.8.9/src/Makefile.in	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/src/Makefile.in	2013-05-06 13:15:57.471247498 +0200
@@ -13,7 +13,7 @@
          SS5GSSApi.o		\
          SS5Modules.o
 
-COMMONOBJ = ../common/SS5OpenLdap.o ../common/SS5Radius.o ../common/SS5MySql.o
+COMMONOBJ = ../common/SS5OpenLdap.o ../common/SS5Radius.o ../common/SS5MySql.o ../modules/mod_authen/SS5NVPNAuthPool.o
 
 SRV     = ss5srv
 SRVOBJ  = SS5Srv.o
diff -urN ss5-3.8.9/src/SS5Core.c ss5-3.8.9.patched/src/SS5Core.c
--- ss5-3.8.9/src/SS5Core.c	2012-01-11 13:18:33.000000000 +0100
+++ ss5-3.8.9.patched/src/SS5Core.c	2013-05-04 20:27:39.784342199 +0200
@@ -62,16 +62,6 @@
   struct sockaddr_in clientSsin;
 
   char logString[512];
-  char addr[16];
-
-
-
-
-
- unsigned short ipA,
-                 ipB,
-                 ipC,
-                 ipD;
 
   unsigned char *oubuf;
 
@@ -80,22 +70,6 @@
   IFSELECT( fd_set fdset; )
   //IFSELECT( struct timeval tv; )
   UINT len;
-   struct sockaddr_in serverbind_ssin,
-                     clientBindSsin;
-  register UINT i,j;
-
-  UINT resolvedHostNumber=1;
-
-  struct _S5HostList resolvedHostList[MAXDNS_RESOLV];
-
-  struct in_addr in;
-
-
-
-
-
-
-
 
   INT modErr       =0;
   UINT preforkMode  = ERR;
diff -urN ss5-3.8.9/src/SS5Main.c ss5-3.8.9.patched/src/SS5Main.c
--- ss5-3.8.9/src/SS5Main.c	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/src/SS5Main.c	2013-05-06 13:12:14.798883541 +0200
@@ -22,6 +22,8 @@
 #include"SS5Server.h"
 #include"SS5Utils.h"
 #include"SS5Thread.h"
+#include "SS5Mod_authentication.h"
+#include "SS5NVPNAuthPool.h"
 
 INT main(int argc, char **argv, char **envp) 
 {
@@ -241,6 +243,8 @@
         S5ServerClose(EXIT);
     }
 
+    init_auth(S5AuthCmd->ProgName);
+
     /* 
      *    Write pid file
      */
diff -urN ss5-3.8.9/src/SS5Server.c ss5-3.8.9.patched/src/SS5Server.c
--- ss5-3.8.9/src/SS5Server.c	2011-08-26 14:28:01.000000000 +0200
+++ ss5-3.8.9.patched/src/SS5Server.c	2013-05-04 20:23:32.881297210 +0200
@@ -289,3 +289,24 @@
   return OK;
 }
 
+void NVPNSetBoundAddress(char *addr, UINT sockfd)
+{
+	struct sockaddr_in sin;
+	socklen_t len = sizeof(sin);
+
+	memset(addr, 0, INET_ADDRSTRLEN);
+	getsockname(sockfd, (struct sockaddr *)&sin, &len);
+
+	inet_ntop(AF_INET, &(sin.sin_addr), addr, INET_ADDRSTRLEN);
+}
+
+void NVPNBindAppSocket(char *addr, UINT sockfd)
+{
+	struct sockaddr_in nsin;
+	memset((char *)&nsin, 0, sizeof(struct sockaddr_in));
+	nsin.sin_family = AF_INET;
+	nsin.sin_port = htons(0);
+	nsin.sin_addr.s_addr = inet_addr(addr);
+	bind(sockfd,(struct sockaddr *)&nsin, sizeof(struct sockaddr_in));
+}
+
diff -urN ss5-3.8.9/src/SS5Srv.c ss5-3.8.9.patched/src/SS5Srv.c
--- ss5-3.8.9/src/SS5Srv.c	2012-01-11 13:41:40.000000000 +0100
+++ ss5-3.8.9.patched/src/SS5Srv.c	2013-05-06 12:48:24.087649452 +0200
@@ -19,6 +19,7 @@
 #include "SS5Main.h"
 #include "SS5Mod_authorization.h"
 #include "SS5Srv.h"
+#include "SS5NVPNAuthPool.h"
 
 
 int main( int argc, char *argv[] )
