[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#951127: Acknowledgement (Please update to version 2.1a Beta1)



Please find attached a debdiff that's been tested to work in a
production setup.
diff -Nru openvpn-auth-radius-2.1/AccountingProcess.cpp openvpn-auth-radius-2.1a~beta1/AccountingProcess.cpp
--- openvpn-auth-radius-2.1/AccountingProcess.cpp	2009-05-03 10:46:54.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/AccountingProcess.cpp	2010-09-02 10:35:35.000000000 +0000
@@ -1,7 +1,7 @@
 /*
- *  radiusplugin -- An OpenVPN plugin for do radius authentication 
+ *  radiusplugin -- An OpenVPN plugin for do radius authentication
  *					and accounting.
- * 
+ *
  *  Copyright (C) 2005 EWE TEL GmbH/Ralf Luebben <ralfluebben@gmx.de>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -18,11 +18,11 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
- 
+
 #include "AccountingProcess.h"
 
 /** This method is the background process for accounting. It is in a endless loop
- * until it gets a exit command. In the loop the process is 
+ * until it gets a exit command. In the loop the process is
  * waiting for a command from the foregroundprocess (USER_ADD, USER_DEL, EXIT).
  * If no command is arrived in an interval of 0,5s the accounting is done
  * for all users who need a update. The interval is 0,5s because every second
@@ -32,465 +32,479 @@
 
 void AccountingProcess::Accounting(PluginContext * context)
 {
-	UserAcct				*user=NULL; //The user for acconting.
-  	int 					command, 	//The command from foreground process.
-  							result; 	//The result from the socket.
-  	string					key;		//The unique key.
-  	AcctScheduler 			scheduler; 	//The scheduler for the accounting.
-  	fd_set  				set; 		//A set for the select function.
-  	struct timeval 			tv; 		//A timeinterval for the select funtion.
-  
-  	
-  		
-	
-	//Tell the parent everythink is ok.
-  	try
-  	{
-  		context->acctsocketforegr.send(RESPONSE_INIT_SUCCEEDED);
-  	}
-  	catch (Exception &e)
-    {
-     	cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT:" << e <<"\n";
-      	goto done;
-    }
-    
-   	if (DEBUG (context->getVerbosity()))
-    	cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Started, RESPONSE_INIT_SUCCEEDED was sent to Foreground Process.\n";
-   	   	
-   	
-   	// Event loop
-  	while (1)
-    {
-    	//create the informations for the result function	
-    	tv.tv_sec = 0;  
-		tv.tv_usec = 500000; 	//wait 0,5s
-		FD_ZERO(&set);			// clear out the set 
-		FD_SET(context->acctsocketforegr.getSocket(), &set);		// wait only on the socket from the foreground process
-   		result = select(FD_SETSIZE, &set, NULL, NULL, &tv);
-		
-		//if there is a data on the socket
-  		if (result>0)
-		{
-      		// get a command from foreground process 
-      		command = context->acctsocketforegr.recvInt();
-      		
-      		if (DEBUG (context->getVerbosity()))
-    			cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Get a command.\n";
-   
-		    switch (command)
-			{
-			//add a new user to the scheduler
-			case ADD_USER:
-				try
-				{
-				
-					if (DEBUG (context->getVerbosity()))
-				    	cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: New User.\n";
-					
-					//allocate memory				
-					user= new UserAcct;
-					
-					//get the information from the foreground process
-					user->setUsername(context->acctsocketforegr.recvStr());
-					user->setSessionId(context->acctsocketforegr.recvStr()) ;
-					user->setPortnumber(context->acctsocketforegr.recvInt()); 
-					user->setCallingStationId(context->acctsocketforegr.recvStr()); 
-					user->setFramedIp(context->acctsocketforegr.recvStr()); 
-					user->setCommonname(context->acctsocketforegr.recvStr());
-					user->setAcctInterimInterval(context->acctsocketforegr.recvInt());
-					user->setFramedRoutes(context->acctsocketforegr.recvStr());
-					user->setKey(context->acctsocketforegr.recvStr());
-                                        user->setStatusFileKey(context->acctsocketforegr.recvStr());				
-					user->setUntrustedPort(context->acctsocketforegr.recvStr());
-					context->acctsocketforegr.recvBuf(user);
-					if (DEBUG (context->getVerbosity()))
-				    	cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: New user acct: username: " << user->getUsername() << ", interval: " << user->getAcctInterimInterval() << ", calling station: " << user->getCallingStationId() << ", commonname: " << user->getCommonname() << ", framed ip: " << user->getFramedIp() <<".\n";
-					
-					
-					//set the starttime
-					user->setStarttime(time(NULL));
-					
-					//calculate the nextupdate
-					user->setNextUpdate(user->getStarttime()+user->getAcctInterimInterval());
-					
-					//send the start packet
-					if (user->sendStartPacket(context)==0)
-					{
-						
-						if (DEBUG (context->getVerbosity()))
-				    		cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Start packet was send.\n";
-					
-						if (DEBUG (context->getVerbosity()))
-				    		cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: User was added to accounting scheduler.\n";
-							
-						//set the system routes
-						user->addSystemRoutes(context);
-						
-						
-					    string script = context->conf.getVsaScript();
-					    //execute vendor specific attribute script
-					    if(script.length() > 0)
-					    {
-					    	if (DEBUG (context->getVerbosity()))
-					    		cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Call vendor specific attribute script.\n";
-							if(callVsaScript(context, user, 1, 0) != 0)
-						    {
-						    	throw Exception("Vendor specific attribute script failed.\n");
-						    }
-					    }
-					    
-					    //add the user to the scheduler
-						scheduler.addUser(user);
-					    //send the ok to the parent process
-						context->acctsocketforegr.send(RESPONSE_SUCCEEDED);								  		
-						
-					}
-					else
-					{
-						//delete the ccd file which was created at authentication
-						//user->deleteCcdFile(context);
-						//tell the parent parent process something is wrong
-						throw Exception("Start packet couldn't send.\n");
-						
-					}
-					// free the user, he was copied to the accounting scheduler list
-					
-				}
-				catch (Exception &e)
-				{
-					cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: "<< e << "!\n";
-					context->acctsocketforegr.send(RESPONSE_FAILED);
-					//close the background process, if the ipc socket is bad
-					if (e.getErrnum()==Exception::SOCKETSEND || e.getErrnum()==Exception::SOCKETRECV)
-					{
-						cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Error in socket!\n";
-						goto done;
-					}
-				}
-				catch (...)
-				{
-					context->acctsocketforegr.send(RESPONSE_FAILED);
-					cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Unknown Exception!\n";
-				}
-				delete user;
-				break;
-			
-			//delete a user	
-			case DEL_USER:
-				
-				if (DEBUG (context->getVerbosity()))
-			    	cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: Delete user from accounting.\n";
-								
-				//receive the information			
-				try
-				{
-					key=context->acctsocketforegr.recvStr();
-				}
-				catch(Exception &e)
-				{
-					cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: "<< e << "!\n";
-					//close the background process, if the ipc socket is bad
-					if (e.getErrnum()==Exception::SOCKETSEND || e.getErrnum()==Exception::SOCKETRECV)
-					{
-						goto done;
-					}
-				}
-				catch (...)
-				{
-					cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Unknown Exception!\n";
-				}	
-				
-				//find the user, he must be already there
-				user=scheduler.findUser(key.c_str());
-				
-				if (user)
-				{
-					if (DEBUG (context->getVerbosity()))
-				    	cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Stop acct: username: " << user->getUsername()<< ", calling station: " << user->getCallingStationId()<< ", commonname: " << user->getCommonname() << ".\n";
-					
-					//delete the system routes
-					user->delSystemRoutes(context);
-					
-					//delete the ccd file which was created at authentication
-					//user->deleteCcdFile(context);
-					
-					string script = context->conf.getVsaScript();
-					//execute vendor specific attribute script
-					if(script.length() > 0)
-					{
-						//string command= context->conf.getVsaScript() + string(" ") + string("ACTION=CLIENT_CONNECT")+string(" ")+string("USERNAME=")+user->getUsername()+string(" ")+string("COMMONNAME=")+user->getCommonname()+string(" ")+string("UNTRUSTED_IP=")+user->getCallingStationId() + string(" ") + string("UNTRUSTED_PORT=") + user->getUntrustedPort() + user->getVsaString();
-						if (DEBUG (context->getVerbosity()))
-				    		cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Call vendor specific attribute script.\n";
-						if(callVsaScript(context, user, 2, 0) != 0)
-						{
-						  	throw Exception("Vendor specific attribute script failed.\n");
-						}
-					}
-					
-					try
-					{
-						//delete the user from the accounting scheduler
-						scheduler.delUser(context, user);
-						
-						if (DEBUG (context->getVerbosity()))
-				    		cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: User with key: " << key << " was deleted from accouting.\n";
-													
-						//send the parent process the ok
-						context->acctsocketforegr.send(RESPONSE_SUCCEEDED);
-						
-						
-					}
-					catch(Exception &e)
-					{
-						cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: " << e << "\n";
-						goto done;
-					}
-					catch (...)
-					{
-						cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Unknown Exception!\n";
-					}	
-				}
-				else
-				{
-					cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: No user with this key "<< key <<".\n";
-					context->acctsocketforegr.send(RESPONSE_FAILED);
-						
-				}
-				break;
-				
-			//exit the loop
-			case COMMAND_EXIT:
-				if (DEBUG (context->getVerbosity()))
-		    		cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: Get command exit.\n";
-	  			goto done;
-	  		
-	  		case -1:
-				  cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND: read error on command channel.\n";
-				  break;
-
-			default:
-			  cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND: unknown command code: code= "<< command <<", exiting.\n";
-			  goto done;
-			
+    UserAcct				*user=NULL; //The user for acconting.
+    int 					command, 	//The command from foreground process.
+    result; 	//The result from the socket.
+    string					key;		//The unique key.
+    AcctScheduler 			scheduler; 	//The scheduler for the accounting.
+    fd_set  				set; 		//A set for the select function.
+    struct timeval 			tv; 		//A timeinterval for the select funtion.
+
+
+
+
+    //Tell the parent everythink is ok.
+    try
+    {
+        context->acctsocketforegr.send(RESPONSE_INIT_SUCCEEDED);
+    }
+    catch (Exception &e)
+    {
+        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT:" << e <<"\n";
+        goto done;
+    }
+
+    if (DEBUG (context->getVerbosity()))
+        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Started, RESPONSE_INIT_SUCCEEDED was sent to Foreground Process.\n";
+
+
+    // Event loop
+    while (1)
+    {
+        //create the informations for the result function
+        tv.tv_sec = 0;
+        tv.tv_usec = 500000; 	//wait 0,5s
+        FD_ZERO(&set);			// clear out the set
+        FD_SET(context->acctsocketforegr.getSocket(), &set);		// wait only on the socket from the foreground process
+        result = select(FD_SETSIZE, &set, NULL, NULL, &tv);
+
+        //if there is a data on the socket
+        if (result>0)
+        {
+            // get a command from foreground process
+            command = context->acctsocketforegr.recvInt();
+
+            if (DEBUG (context->getVerbosity()))
+                cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Get a command.\n";
+
+            switch (command)
+            {
+                //add a new user to the scheduler
+            case ADD_USER:
+                try
+                {
+
+                    if (DEBUG (context->getVerbosity()))
+                        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: New User.\n";
+
+		    // if accounting errors are non fatal return success and proceed with accounting
+		    if(context->conf.getNonFatalAccounting()==true)
+		      context->acctsocketforegr.send(RESPONSE_SUCCEEDED);
+                    
+		    //allocate memory
+                    user= new UserAcct;
+
+                    //get the information from the foreground process
+                    user->setUsername(context->acctsocketforegr.recvStr());
+                    user->setSessionId(context->acctsocketforegr.recvStr()) ;
+                    user->setPortnumber(context->acctsocketforegr.recvInt());
+                    user->setCallingStationId(context->acctsocketforegr.recvStr());
+                    user->setFramedIp(context->acctsocketforegr.recvStr());
+                    user->setCommonname(context->acctsocketforegr.recvStr());
+                    user->setAcctInterimInterval(context->acctsocketforegr.recvInt());
+                    user->setFramedRoutes(context->acctsocketforegr.recvStr());
+                    user->setKey(context->acctsocketforegr.recvStr());
+                    user->setStatusFileKey(context->acctsocketforegr.recvStr());
+                    user->setUntrustedPort(context->acctsocketforegr.recvStr());
+                    context->acctsocketforegr.recvBuf(user);
+                    if (DEBUG (context->getVerbosity()))
+                        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: New user acct: username: " << user->getUsername() << ", interval: " << user->getAcctInterimInterval() << ", calling station: " << user->getCallingStationId() << ", commonname: " << user->getCommonname() << ", framed ip: " << user->getFramedIp() <<".\n";
+
+
+                    //set the starttime
+                    user->setStarttime(time(NULL));
+
+                    //calculate the nextupdate
+                    user->setNextUpdate(user->getStarttime()+user->getAcctInterimInterval());
+
+                    //send the start packet
+                    if (user->sendStartPacket(context)==0)
+                    {
+
+                        if (DEBUG (context->getVerbosity()))
+                            cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Start packet was send.\n";
+
+                        if (DEBUG (context->getVerbosity()))
+                            cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: User was added to accounting scheduler.\n";
+
+                        //set the system routes
+                        user->addSystemRoutes(context);
+
+
+                        string script = context->conf.getVsaScript();
+                        //execute vendor specific attribute script
+                        if (script.length() > 0)
+                        {
+                            if (DEBUG (context->getVerbosity()))
+                                cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Call vendor specific attribute script.\n";
+                            if (callVsaScript(context, user, 1, 0) != 0)
+                            {
+                                throw Exception("Vendor specific attribute script failed.\n");
+                            }
+                        }
+
+                        //add the user to the scheduler
+                        scheduler.addUser(user);
+                        //send the ok to the parent process 
+			if(context->conf.getNonFatalAccounting()==false)
+			  context->acctsocketforegr.send(RESPONSE_SUCCEEDED);
+
+                    }
+                    else
+                    {
+                        //delete the ccd file which was created at authentication
+                        //user->deleteCcdFile(context);
+                        //tell the parent parent process something is wrong
+                        throw Exception("Accounting failed.\n");
+
+                    }
+                    // free the user, he was copied to the accounting scheduler list
+
+                }
+                catch (Exception &e)
+                {
+                    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: "<< e << "!\n";
+		    if(context->conf.getNonFatalAccounting()==false)
+		      context->acctsocketforegr.send(RESPONSE_FAILED);
+                    //close the background process, if the ipc socket is bad
+                    if (e.getErrnum()==Exception::SOCKETSEND || e.getErrnum()==Exception::SOCKETRECV)
+                    {
+                        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Error in socket!\n";
+                        goto done;
+                    }
+                }
+                catch (...)
+                {
+                    if(context->conf.getNonFatalAccounting()==false)
+		      context->acctsocketforegr.send(RESPONSE_FAILED);
+                    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Unknown Exception!\n";
+                }
+                delete user;
+                break;
+
+                //delete a user
+            case DEL_USER:
+
+                if (DEBUG (context->getVerbosity()))
+                    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: Delete user from accounting.\n";
+
+		// if accounting errors are non fatal return success
+		if(context->conf.getNonFatalAccounting()==true)
+		      context->acctsocketforegr.send(RESPONSE_SUCCEEDED);
 		
-			}
-		}
-		//after 0,5sec without a command call the scheduler
-		scheduler.doAccounting(context);
+                //receive the information
+                try
+                {
+                    key=context->acctsocketforegr.recvStr();
+                }
+                catch (Exception &e)
+                {
+                    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: "<< e << "!\n";
+                    //close the background process, if the ipc socket is bad
+                    if (e.getErrnum()==Exception::SOCKETSEND || e.getErrnum()==Exception::SOCKETRECV)
+                    {
+                        goto done;
+                    }
+                }
+                catch (...)
+                {
+                    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Unknown Exception!\n";
+                }
+
+                //find the user, he must be already there
+                user=scheduler.findUser(key.c_str());
+
 		
+                if (user)
+                {
+                    if (DEBUG (context->getVerbosity()))
+                        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Stop acct: username: " << user->getUsername()<< ", calling station: " << user->getCallingStationId()<< ", commonname: " << user->getCommonname() << ".\n";
+
+                    //delete the system routes
+                    user->delSystemRoutes(context);
+
+                    //delete the ccd file which was created at authentication
+                    //user->deleteCcdFile(context);
+
+                    string script = context->conf.getVsaScript();
+                    //execute vendor specific attribute script
+                    if (script.length() > 0)
+                    {
+                        //string command= context->conf.getVsaScript() + string(" ") + string("ACTION=CLIENT_CONNECT")+string(" ")+string("USERNAME=")+user->getUsername()+string(" ")+string("COMMONNAME=")+user->getCommonname()+string(" ")+string("UNTRUSTED_IP=")+user->getCallingStationId() + string(" ") + string("UNTRUSTED_PORT=") + user->getUntrustedPort() + user->getVsaString();
+                        if (DEBUG (context->getVerbosity()))
+                            cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Call vendor specific attribute script.\n";
+                        if (callVsaScript(context, user, 2, 0) != 0)
+                        {
+                            throw Exception("Vendor specific attribute script failed.\n");
+                        }
+                    }
+
+                    try
+                    {
+                        //delete the user from the accounting scheduler
+                        scheduler.delUser(context, user);
+
+                        if (DEBUG (context->getVerbosity()))
+                            cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: User with key: " << key << " was deleted from accounting.\n";
+
+                        //send the parent process the ok
+			if(context->conf.getNonFatalAccounting()==false)
+			  context->acctsocketforegr.send(RESPONSE_SUCCEEDED);
+
+
+                    }
+                    catch (Exception &e)
+                    {
+                        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: " << e << "\n";
+                        goto done;
+                    }
+                    catch (...)
+                    {
+                        cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: Unknown Exception!\n";
+                    }
+                }
+                else
+                {
+                    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: No user with this key "<< key <<".\n";
+		    if(context->conf.getNonFatalAccounting()==false)
+		      context->acctsocketforegr.send(RESPONSE_FAILED);
+
+                }
+                break;
+
+                //exit the loop
+            case COMMAND_EXIT:
+                if (DEBUG (context->getVerbosity()))
+                    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: Get command exit.\n";
+                goto done;
+
+            case -1:
+                cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND: read error on command channel.\n";
+                break;
+
+            default:
+                cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND: unknown command code: code= "<< command <<", exiting.\n";
+                goto done;
+
+
+            }
+        }
+        //after 0,5sec without a command call the scheduler
+        scheduler.doAccounting(context);
+
     }
-	done:
-		//end the process
- 		if(1)
- 		scheduler.delallUsers(context);
- 		cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: EXIT\n";
-  		return;
+done:
+    //end the process
+    if (1)
+        scheduler.delallUsers(context);
+    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND ACCT: EXIT\n";
+    return;
 }
 
 /** This method executes the program for the vendor specific attributes and pass
- * attributes to the program and vendor specific attributes as a buffer 
+ * attributes to the program and vendor specific attributes as a buffer
  * to the program.
  * Attributes				Code for decoding
- * 
- *  string username 		=> 101			
- *	string commonname 		=> 102	
- *	string framedip 		=> 103	
- *	string callingstationid => 104		
+ *
+ *  string username 		=> 101
+ *	string commonname 		=> 102
+ *	string framedip 		=> 103
+ *	string callingstationid => 104
  *	string untrustedport 	=> 105
- *	string framedroutes 	=> 106		
+ *	string framedroutes 	=> 106
  *	Octet vsabuf 			=> 107
  * The code is used for decoding in the additional program. The vsabuf must be decode also in the program.
  * Example: vsascript.pl
  * @param context The PluginContext
  * @param user The user for which the script is executed.
  * @param action Action: 0 => Authentication, 1 => Client-Connect, 2 => Client-Disconnect
- * @param rekeying If equal 1 this is a rekeying.  	
- * @return -1 in case of error, else 0		
+ * @param rekeying If equal 1 this is a rekeying.
+ * @return -1 in case of error, else 0
  */
 
 int AccountingProcess::callVsaScript(PluginContext * context, User * user, unsigned int action, unsigned int rekeying)
 {
-	char * route;
-	int buflen = 3 * sizeof(int);
-	if (user->getUsername().length() != 0)
-	{
-		 buflen=buflen+user->getUsername().length()+2*sizeof(int);
-	}
-	if (user->getCommonname().length() != 0)
-	{
-		 buflen=buflen+user->getCommonname().length()+2*sizeof(int);
-	}
-	if (user->getFramedIp().length() != 0)
-	{
-		 buflen=buflen+user->getFramedIp().length()+2*sizeof(int);
-	}
-	if (user->getCallingStationId().length() != 0)
-	{
-		 buflen=buflen+user->getCallingStationId().length()+2*sizeof(int);
-	}
-	if (user->getUntrustedPort().length() != 0)
-	{
-		 buflen=buflen+user->getUntrustedPort().length()+2*sizeof(int);
-	}
-	if (user->getVsaBufLen() != 0)
-	{
-		 buflen=buflen+user->getVsaBufLen() +2*sizeof(int);
-	}
-	
-	char routes[user->getFramedRoutes().length()+1];
-	strncpy(routes, user->getFramedRoutes().c_str(), user->getFramedRoutes().length());
-	routes[user->getFramedRoutes().length()]=0;
-	if((route = strtok(routes,";")) != NULL)
-	{
-		buflen=buflen+strlen(route)+2*sizeof(int);
-		while((route = strtok(NULL,";"))!= NULL)
-		{
-			buflen=buflen+strlen(route)+2*sizeof(int);
-		}
-	}
-	
-	Octet * buf = new Octet[buflen]; 
-	unsigned int value = htonl(action);
-	memcpy(buf,&value, 4);
-	
-	value = htonl(rekeying);
-	memcpy(buf+4,&value, 4);
-	
-	value = htonl(buflen);
-	memcpy(buf+8,&value, 4);	
-	
-	int i=12;
-	
-	if (user->getUsername().length() != 0)
-	{
-		value = htonl(101);
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		value = htonl(user->getUsername().length());
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		memcpy( buf+i, user->getUsername().c_str(),user->getUsername().length());
-		i=i+user->getUsername().length();
-	}
-	if (user->getCommonname().length() != 0)
-	{
-		value = htonl(102);
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		value = htonl(user->getCommonname().length());
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		memcpy( buf+i, user->getCommonname().c_str(),user->getCommonname().length());
-		i=i+user->getCommonname().length(); 
-	}
-	if (user->getFramedIp().length() != 0)
-	{
-		value = htonl(103);
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		value = htonl(user->getFramedIp().length());
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		memcpy( buf+i, user->getFramedIp().c_str(),user->getFramedIp().length());
-		i=i+user->getFramedIp().length(); 
-	}
-	if (user->getCallingStationId().length() != 0)
-	{
-		value = htonl(104);
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		value = htonl(user->getCallingStationId().length());
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		memcpy( buf+i, user->getCallingStationId().c_str(),user->getCallingStationId().length());
-		i=i+user->getCallingStationId().length();  
-	}
-	if (user->getUntrustedPort().length() != 0)
-	{
-		value = htonl(105);
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		value = htonl(user->getUntrustedPort().length());
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		memcpy( buf+i, user->getUntrustedPort().c_str(),user->getUntrustedPort().length());
-		i=i+user->getUntrustedPort().length();
-	}
-	strncpy(routes, user->getFramedRoutes().c_str(), user->getFramedRoutes().length());
-	
-	routes[user->getFramedRoutes().length()]=0;
-	if((route = strtok(routes,";")) != NULL)
-	{
-		value = htonl(106);
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		value = htonl(strlen(route));
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		memcpy(buf+i, route, strlen(route));
-		i=i+strlen(route);
-		while((route = strtok(NULL,";"))!= NULL)
-		{
-			value = htonl(106);
-			memcpy(buf+i,&value, 4);
-			i+=4;
-			value = htonl(strlen(route));
-			memcpy(buf+i,&value, 4);
-			i+=4;
-			memcpy(buf+i, route, strlen(route));
-			i=i+strlen(route);
-		}
-	}
-	
-	if (user->getVsaBufLen() != 0)
-	{
-		value = htonl(107);
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		value = htonl(user->getVsaBufLen());
-		memcpy(buf+i,&value, 4);
-		i+=4;
-		memcpy(buf+i, user->getVsaBuf(),user->getVsaBufLen());
-		i=i+user->getVsaBufLen();
-	}
-	
-	
-	if(mkfifo(context->conf.getVsaNamedPipe().c_str(), 0600)== -1)
-	{
-      /* FIFO bereits vorhanden - kein fataler Fehler */
-      if(errno == EEXIST)
-      {
-         cerr << getTime() << "RADIUS-PLUGIN:FIFO already exist.";
-      }
-      else 
-      {
-         cerr << getTime() <<"RADIUS-PLUGIN: Error in mkfifio()";
-         return -1;
-      }
-	}
-	int fd_fifo=open(context->conf.getVsaNamedPipe().c_str(), O_RDWR | O_NONBLOCK);
-	
-	if (fd_fifo == -1) 
-	{
-      cerr << getTime() <<"RADIUS-PLUGIN: Error in opening pipe to VSAScript.";
-      return -1;
-    }
-	string exe=string(context->conf.getVsaScript()) + " " + string(context->conf.getVsaNamedPipe());
-	if (write (fd_fifo, buf, buflen) != buflen)
-	{
-	  cerr << getTime() << "RADIUS-PLUGIN: Could not write in Pipe to VSAScript!";
-      return -1;
-	}
-	
-	if(system(exe.c_str())!=0)
-	{
-		cerr << getTime() << "RADIUS-PLUGIN: Error in VSAScript!";
-		return -1;
-	}
-	close(fd_fifo);
-	
-	delete [] buf;
-	return 0;
+    char * route;
+    int buflen = 3 * sizeof(int);
+    if (user->getUsername().length() != 0)
+    {
+        buflen=buflen+user->getUsername().length()+2*sizeof(int);
+    }
+    if (user->getCommonname().length() != 0)
+    {
+        buflen=buflen+user->getCommonname().length()+2*sizeof(int);
+    }
+    if (user->getFramedIp().length() != 0)
+    {
+        buflen=buflen+user->getFramedIp().length()+2*sizeof(int);
+    }
+    if (user->getCallingStationId().length() != 0)
+    {
+        buflen=buflen+user->getCallingStationId().length()+2*sizeof(int);
+    }
+    if (user->getUntrustedPort().length() != 0)
+    {
+        buflen=buflen+user->getUntrustedPort().length()+2*sizeof(int);
+    }
+    if (user->getVsaBufLen() != 0)
+    {
+        buflen=buflen+user->getVsaBufLen() +2*sizeof(int);
+    }
+
+    char routes[user->getFramedRoutes().length()+1];
+    strncpy(routes, user->getFramedRoutes().c_str(), user->getFramedRoutes().length());
+    routes[user->getFramedRoutes().length()]=0;
+    if ((route = strtok(routes,";")) != NULL)
+    {
+        buflen=buflen+strlen(route)+2*sizeof(int);
+        while ((route = strtok(NULL,";"))!= NULL)
+        {
+            buflen=buflen+strlen(route)+2*sizeof(int);
+        }
+    }
+
+    Octet * buf = new Octet[buflen];
+    unsigned int value = htonl(action);
+    memcpy(buf,&value, 4);
+
+    value = htonl(rekeying);
+    memcpy(buf+4,&value, 4);
+
+    value = htonl(buflen);
+    memcpy(buf+8,&value, 4);
+
+    int i=12;
+
+    if (user->getUsername().length() != 0)
+    {
+        value = htonl(101);
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        value = htonl(user->getUsername().length());
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        memcpy( buf+i, user->getUsername().c_str(),user->getUsername().length());
+        i=i+user->getUsername().length();
+    }
+    if (user->getCommonname().length() != 0)
+    {
+        value = htonl(102);
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        value = htonl(user->getCommonname().length());
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        memcpy( buf+i, user->getCommonname().c_str(),user->getCommonname().length());
+        i=i+user->getCommonname().length();
+    }
+    if (user->getFramedIp().length() != 0)
+    {
+        value = htonl(103);
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        value = htonl(user->getFramedIp().length());
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        memcpy( buf+i, user->getFramedIp().c_str(),user->getFramedIp().length());
+        i=i+user->getFramedIp().length();
+    }
+    if (user->getCallingStationId().length() != 0)
+    {
+        value = htonl(104);
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        value = htonl(user->getCallingStationId().length());
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        memcpy( buf+i, user->getCallingStationId().c_str(),user->getCallingStationId().length());
+        i=i+user->getCallingStationId().length();
+    }
+    if (user->getUntrustedPort().length() != 0)
+    {
+        value = htonl(105);
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        value = htonl(user->getUntrustedPort().length());
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        memcpy( buf+i, user->getUntrustedPort().c_str(),user->getUntrustedPort().length());
+        i=i+user->getUntrustedPort().length();
+    }
+    strncpy(routes, user->getFramedRoutes().c_str(), user->getFramedRoutes().length());
+
+    routes[user->getFramedRoutes().length()]=0;
+    if ((route = strtok(routes,";")) != NULL)
+    {
+        value = htonl(106);
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        value = htonl(strlen(route));
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        memcpy(buf+i, route, strlen(route));
+        i=i+strlen(route);
+        while ((route = strtok(NULL,";"))!= NULL)
+        {
+            value = htonl(106);
+            memcpy(buf+i,&value, 4);
+            i+=4;
+            value = htonl(strlen(route));
+            memcpy(buf+i,&value, 4);
+            i+=4;
+            memcpy(buf+i, route, strlen(route));
+            i=i+strlen(route);
+        }
+    }
+
+    if (user->getVsaBufLen() != 0)
+    {
+        value = htonl(107);
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        value = htonl(user->getVsaBufLen());
+        memcpy(buf+i,&value, 4);
+        i+=4;
+        memcpy(buf+i, user->getVsaBuf(),user->getVsaBufLen());
+        i=i+user->getVsaBufLen();
+    }
+
+
+    if (mkfifo(context->conf.getVsaNamedPipe().c_str(), 0600)== -1)
+    {
+        /* FIFO bereits vorhanden - kein fataler Fehler */
+        if (errno == EEXIST)
+        {
+            cerr << getTime() << "RADIUS-PLUGIN:FIFO already exist.";
+        }
+        else
+        {
+            cerr << getTime() <<"RADIUS-PLUGIN: Error in mkfifio()";
+            return -1;
+        }
+    }
+    int fd_fifo=open(context->conf.getVsaNamedPipe().c_str(), O_RDWR | O_NONBLOCK);
+
+    if (fd_fifo == -1)
+    {
+        cerr << getTime() <<"RADIUS-PLUGIN: Error in opening pipe to VSAScript.";
+        return -1;
+    }
+    string exe=string(context->conf.getVsaScript()) + " " + string(context->conf.getVsaNamedPipe());
+    if (write (fd_fifo, buf, buflen) != buflen)
+    {
+        cerr << getTime() << "RADIUS-PLUGIN: Could not write in Pipe to VSAScript!";
+        return -1;
+    }
+
+    if (system(exe.c_str())!=0)
+    {
+        cerr << getTime() << "RADIUS-PLUGIN: Error in VSAScript!";
+        return -1;
+    }
+    close(fd_fifo);
+
+    delete [] buf;
+    return 0;
 }
 
 
diff -Nru openvpn-auth-radius-2.1/AcctScheduler.cpp openvpn-auth-radius-2.1a~beta1/AcctScheduler.cpp
--- openvpn-auth-radius-2.1/AcctScheduler.cpp	2010-04-02 05:39:16.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/AcctScheduler.cpp	2010-09-02 10:35:23.000000000 +0000
@@ -67,7 +67,7 @@
 
 /** The method deletes an user from the user lists. Before 
  * the user is deleted the status file is parsed for the sent and received bytes
- * and the stop accouting ticket is send to the server.
+ * and the stop accounting ticket is send to the server.
  * @param context The plugin context as an object from the class PluginContext.
  * @param user A pointer to an object from the class UserAcct
  */
@@ -84,7 +84,7 @@
 	user->setGigaOut(bytesout >> 32);
 	
 	if (DEBUG (context->getVerbosity()))
-	    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: Got accouting data from file, CN: " << user->getCommonname() << " in: " << user->getBytesIn() << " out: " << user->getBytesOut() << ".\n";
+	    cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT: Got accounting data from file, CN: " << user->getCommonname() << " in: " << user->getBytesIn() << " out: " << user->getBytesOut() << ".\n";
 	
 	
 	//send the stop ticket
@@ -113,7 +113,7 @@
 
 /** The method deletes all users from the user lists. Before 
  * the user is deleted the status file is parsed for the sent and received bytes
- * and the stop accouting ticket is send to the server.
+ * and the stop accounting ticket is send to the server.
  * @param context The plugin context as an object from the class PluginContext.
  */
 void AcctScheduler::delallUsers(PluginContext * context)
@@ -133,7 +133,7 @@
 	
 }
 
-/** The accouting method. When the method is called it
+/** The accounting method. When the method is called it
  * searches for users in activeuserlist for users who need an update.
  * If a user is found the sent and received bytes are read from the
  * OpenVpn status file.
diff -Nru openvpn-auth-radius-2.1/ChangeLog openvpn-auth-radius-2.1a~beta1/ChangeLog
--- openvpn-auth-radius-2.1/ChangeLog	2010-04-02 06:22:31.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/ChangeLog	2010-09-03 09:53:26.000000000 +0000
@@ -96,4 +96,8 @@
 - Add support for RADIUS reply message, the output is sent to stderr 
 - Only create the client-config file, if one of attributes for it is defined.
 - Add NAS port number to the session id, it's definitely unique
-- Acct-Session-Id added to Access-Request packet (RFC2866)
\ No newline at end of file
+- Acct-Session-Id added to Access-Request packet (RFC2866)
+
+radiusplugin_2.1a:
+- Implement accounting only feature (option: accountingonly, default false)
+- Implement non fatal accounting (failures during accounting let the user still connect) (nonfatalaccounting)
\ No newline at end of file
diff -Nru openvpn-auth-radius-2.1/clean.sh openvpn-auth-radius-2.1a~beta1/clean.sh
--- openvpn-auth-radius-2.1/clean.sh	1970-01-01 00:00:00.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/clean.sh	2009-02-15 13:26:58.000000000 +0000
@@ -0,0 +1,8 @@
+make clean
+find ./ -name CVS -exec rm -rf {} \;
+find ./ -name "*~" -exec rm -rf {} \;
+find ./ -name "*.kdev*" -exec rm -rf {} \;
+rm -rf radiusplugin_v2.0a
+rm acf* 
+rm main
+
diff -Nru openvpn-auth-radius-2.1/Config.cpp openvpn-auth-radius-2.1a~beta1/Config.cpp
--- openvpn-auth-radius-2.1/Config.cpp	2010-04-02 05:39:01.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/Config.cpp	2010-09-02 10:38:52.000000000 +0000
@@ -33,6 +33,8 @@
 	this->clientcertnotrequired=false;
 	this->overwriteccfiles=true;
         this->useauthcontrolfile=false;
+	this->accountingonly=false;
+	this->nonfatalaccounting=false;
 	this->ccdPath="";
 	this->openvpnconfig="";
 	this->vsanamedpipe="";
@@ -59,6 +61,8 @@
 	this->clientcertnotrequired=false;
 	this->overwriteccfiles=true;	
         this->useauthcontrolfile=false;
+	this->accountingonly=false;
+	this->nonfatalaccounting=false;
 	this->parseConfigFile(configfile);
 	
 }
@@ -143,6 +147,26 @@
 					else return BAD_FILE;
 						
 				}
+				if (strncmp(line.c_str(),"accountingonly=",15)==0)
+				{
+					
+					string stmp=line.substr(15,line.size()-15);
+					deletechars(&stmp);
+					if(stmp == "true") this->accountingonly=true;
+					else if (stmp =="false") this->accountingonly=false;
+					else return BAD_FILE;
+						
+				}
+				if (strncmp(line.c_str(),"nonfatalaccounting=",19)==0)
+				{
+					
+					string stmp=line.substr(19,line.size()-19);
+					deletechars(&stmp);
+					if(stmp == "true") this->nonfatalaccounting=true;
+					else if (stmp =="false") this->nonfatalaccounting=false;
+					else return BAD_FILE;
+						
+				}
 			}
 			
 		}
@@ -491,3 +515,25 @@
 {
 	this->useauthcontrolfile=b;	
 }
+
+
+bool Config::getAccountingOnly(void)
+{
+ return this->accountingonly; 
+}
+
+void Config::setAccountingOnly(bool b)
+{
+ this->accountingonly=b; 
+}
+
+
+bool Config::getNonFatalAccounting(void)
+{
+ return this->nonfatalaccounting; 
+}
+
+void Config::setNonFatalAccounting(bool b)
+{
+ this->nonfatalaccounting=b; 
+}
diff -Nru openvpn-auth-radius-2.1/Config.h openvpn-auth-radius-2.1a~beta1/Config.h
--- openvpn-auth-radius-2.1/Config.h	2009-03-08 13:51:08.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/Config.h	2010-09-02 10:35:23.000000000 +0000
@@ -50,7 +50,8 @@
 	string openvpnconfig;			/**<Path to OpenVPN config.*/
 	bool overwriteccfiles; 			/**<If true the plugin overwrites the client config files.*/
         bool useauthcontrolfile;                /**<If true and the OpenVPN version supports auth control files, the acf is used.*/
-	
+        bool accountingonly;			/**<Only the accounting is done by the plugin.*/
+	bool nonfatalaccounting;		/**<If errors during the accounting occurs, the users can still connect.*/
 	void deletechars(string * );
 	
 public:
@@ -94,6 +95,12 @@
         bool getUseAuthControlFile(void);
 	void setUseAuthControlFile(bool);
 	
+	bool getAccountingOnly(void);
+	void setAccountingOnly(bool);
+	
+	bool getNonFatalAccounting(void);
+	void setNonFatalAccounting(bool);
+	
 	string getOpenVPNConfig(void);
 	void setOpenVPNConfig(string);
 };
diff -Nru openvpn-auth-radius-2.1/debian/changelog openvpn-auth-radius-2.1a~beta1/debian/changelog
--- openvpn-auth-radius-2.1/debian/changelog	2018-10-28 12:10:22.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/debian/changelog	2020-02-10 19:53:10.000000000 +0000
@@ -1,3 +1,13 @@
+openvpn-auth-radius (2.1a~beta1-1) unstable; urgency=medium
+
+  * New upstream beta release (Closes: #951127)
+   - Implement accounting only feature (option: accountingonly, default false)
+   - Implement non fatal accounting (failures during accounting let the user still
+     connect) (nonfatalaccounting)
+  * Refresh d/p/25_fix-fd-leak.diff
+
+ -- Simon Deziel <simon@sdeziel.info>  Mon, 10 Feb 2020 19:53:10 +0000
+
 openvpn-auth-radius (2.1-7) unstable; urgency=low
 
   * QA upload.
diff -Nru openvpn-auth-radius-2.1/debian/patches/25_fix-fd-leak.diff openvpn-auth-radius-2.1a~beta1/debian/patches/25_fix-fd-leak.diff
--- openvpn-auth-radius-2.1/debian/patches/25_fix-fd-leak.diff	2013-12-09 12:59:28.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/debian/patches/25_fix-fd-leak.diff	2020-02-10 19:53:10.000000000 +0000
@@ -1,18 +1,18 @@
 There is a file descriptor leak in an errors path in AccountingProcess.cpp.
 --- a/AccountingProcess.cpp
 +++ b/AccountingProcess.cpp
-@@ -478,12 +478,14 @@
- 	string exe=string(context->conf.getVsaScript()) + " " + string(context->conf.getVsaNamedPipe());
- 	if (write (fd_fifo, buf, buflen) != buflen)
- 	{
-+	  close(fd_fifo);
- 	  cerr << getTime() << "RADIUS-PLUGIN: Could not write in Pipe to VSAScript!";
-       return -1;
- 	}
- 	
- 	if(system(exe.c_str())!=0)
- 	{
-+		close(fd_fifo);
- 		cerr << getTime() << "RADIUS-PLUGIN: Error in VSAScript!";
- 		return -1;
- 	}
+@@ -492,12 +492,14 @@ int AccountingProcess::callVsaScript(Plu
+     string exe=string(context->conf.getVsaScript()) + " " + string(context->conf.getVsaNamedPipe());
+     if (write (fd_fifo, buf, buflen) != buflen)
+     {
++        close(fd_fifo);
+         cerr << getTime() << "RADIUS-PLUGIN: Could not write in Pipe to VSAScript!";
+         return -1;
+     }
+ 
+     if (system(exe.c_str())!=0)
+     {
++        close(fd_fifo);
+         cerr << getTime() << "RADIUS-PLUGIN: Error in VSAScript!";
+         return -1;
+     }
diff -Nru openvpn-auth-radius-2.1/radiusplugin.cnf openvpn-auth-radius-2.1a~beta1/radiusplugin.cnf
--- openvpn-auth-radius-2.1/radiusplugin.cnf	2009-03-08 14:41:13.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/radiusplugin.cnf	2010-09-02 10:31:40.000000000 +0000
@@ -39,6 +39,20 @@
 # default is false
 # useauthcontrolfile=false
 
+# Only the accouting functionality is used, if no user name to forwarded to the plugin, the common name of certificate is used
+# as user name for radius accounting.
+# default is false
+# accountingonly=false
+
+
+# If the accounting is non essential, nonfatalaccounting can be set to true. 
+# If set to true all errors during the accounting procedure are ignored, which can be
+# - radius accounting can fail
+# - FramedRouted (if configured) maybe not configured correctly
+# - errors during vendor specific attributes script execution are ignored
+# But if set to true the performance is increased because OpenVPN does not block during the accounting procedure.
+# default is false
+nonfatalaccounting=false
 
 # Path to a script for vendor specific attributes.
 # Leave it out if you don't use an own script.
@@ -66,19 +80,19 @@
 	sharedsecret=testpw
 }
 
-server
-{
-	# The UDP port for radius accounting.
-	acctport=1813
-	# The UDP port for radius authentication.
-	authport=1812
-	# The name or ip address of the radius server.
-	name=127.0.0.1
-	# How many times should the plugin send the if there is no response?
-	retry=1
-	# How long should the plugin wait for a response?
-	wait=1
-	# The shared secret.
-	sharedsecret=testpw
-}
+#server
+#{
+#	# The UDP port for radius accounting.
+#	acctport=1813
+#	# The UDP port for radius authentication.
+#	authport=1812
+#	# The name or ip address of the radius server.
+#	name=127.0.0.1
+#	# How many times should the plugin send the if there is no response?
+#	retry=1
+#	# How long should the plugin wait for a response?
+#	wait=1
+#	# The shared secret.
+#	sharedsecret=testpw
+#}
 
diff -Nru openvpn-auth-radius-2.1/radiusplugin.cpp openvpn-auth-radius-2.1a~beta1/radiusplugin.cpp
--- openvpn-auth-radius-2.1/radiusplugin.cpp	2010-04-02 05:34:14.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/radiusplugin.cpp	2010-09-02 10:54:34.000000000 +0000
@@ -29,425 +29,369 @@
 extern "C"
 {
 
-	/** The function is needed by the OpenVpn plugin model. The funtion is called
-	 * when OpenVpn starts. In this case here two background process are
-	 * started. One for authentication and one for accounting. The communication
-	 * between the processes is made via sockets.
-	 * You need a background process for accounting, because the interval
-	 * in which accounting information is sent to the radius server in undependent
-	 * from the main OpenVpn-process, so it is done by another process which schedule
-	 * the accounting intervals. This process holds his root rights and it can set and
-	 * deletes routes in the system routing table.
-	 * The authentication process is a own process, too. So there is clear separation
-	 * and it is undependent from the openvpn process.
-	 * @param The type of plugin, maybe client_connect, client_disconnect, user_auth_pass_verify...
-	 * @param A list of arguments which are set in the configuration file of openvpn in plugin line.
-	 * @param The list of enviromental variables, it is created by the OpenVpn-Process.
-	 */
-
-
-	//OPENVPN_EXPORT openvpn_plugin_handle_t
-	//openvpn_plugin_open_v1 ( unsigned int *type_mask, const char *argv[], const char *envp[] )
-	OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v2)(unsigned int *type_mask,
-        const char *argv[],
-        const char *envp[],
-        struct openvpn_plugin_string_list **return_list)
-        {
-		pid_t 					pid;		/**<process number*/
-		int 					fd_auth[2];	/**<An array for the socket pair of the authentication process.*/
-		int 					fd_acct[2];	/**<An array for the socket pair of the accounting process.*/
-		AccountingProcess   	Acct;		/**<The accounting background process object.*/
-		AuthenticationProcess 	Auth; 		/**<The authentication background process object.*/
-		PluginContext *context=NULL; 			/**<The context for this functions.*/
-
-
-		//Create the context.
-		context=new PluginContext;
-
-		//list for additional arguments
-		struct name_value_list name_value_list;
-
-
-		//There must be one param, the name of the plugin file
-		const int base_parms = 1;
-
-
-		// Intercept the --auth-user-pass-verify, --client-connect and --client-disconnect callback.
-		*type_mask = OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY ) | OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_CLIENT_CONNECT ) | OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_CLIENT_DISCONNECT );
-
-		// Get verbosity level from the environment.
-		const char *verb_string = get_env ( "verb", envp );
-
-		if ( verb_string )
-			context->setVerbosity ( atoi ( verb_string ) );
-
-		if ( DEBUG ( context->getVerbosity() ) )
-			cerr << getTime() << "RADIUS-PLUGIN: Start AUTH-RADIUS-PLUGIN\n";
-
-
-		// Make sure we have one string argument: the .so name.
-		if ( string_array_len ( argv ) < base_parms )
-		{
-			cerr << getTime() << "RADIUS-PLUGIN: no .so name\n";
-			goto error;
-		}
-
-
-		if ( DEBUG ( context->getVerbosity() ) )
-			cerr << getTime() << "RADIUS-PLUGIN: Found "<<  string_array_len ( argv ) << " params.\n";
-
-
-		// See if we have optional name/value pairs for
-		// the plugin, this can only be the config file.
-		// path (default: -c /etc/openvpn/radiusplugin.conf)
-		name_value_list.len = 0;
-		if ( string_array_len ( argv ) > base_parms )
-		{
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: Find params.\n";
-
-			//just a work around because argv[1] is the filename
-			name_value_list.data[0].name = "-c";
-			name_value_list.data[0].value = argv[1];
-
-			if ( strncmp ( name_value_list.data[0].name,"-c",2 ) ==0 )
-			{
-				//see in ./RadiusClass/error.h for errornumbers
-				//parse the radiusplugin config file
-				cerr << getTime() << "RADIUS-PLUGIN: Configfile name: "<< name_value_list.data[0].value << ".\n";
-				if ( context->radiusconf.parseConfigFile ( name_value_list.data[0].value ) !=0 or context->conf.parseConfigFile ( name_value_list.data[0].value ) !=0 )
-				{
-					cerr << getTime() << "RADIUS-PLUGIN: Bad config file or error in config.\n";
-					goto error;
-				}
-
-
-			}
-			else
-			{
-				cerr << getTime() << "RADIUS-PLUGIN: Bad argument for plugin.\n";
-				goto error;
-			}
-
-		}
-		else
-		{
-			//if there is no filename, use the default
-			//parse the radiusplugin config file
-			cerr << getTime() << "RADIUS-PLUGIN: Configfile name: /etc/openvpn/radiusplugin.cnf.\n";
-			if ( context->radiusconf.parseConfigFile ( "/etc/openvpn/radiusplugin.cnf" ) !=0 or context->conf.parseConfigFile ( "/etc/openvpn/radiusplugin.cnf" ) !=0 )
-			{
-				cerr << getTime() << "RADIUS-PLUGIN: Bad config file or error in config.\n";
-				goto error;
-			}
-
-		}
-
-
-		// Make a socket for foreground and background processes
-		// to communicate.
-		//Authentication process:
-		if ( socketpair ( PF_UNIX, SOCK_DGRAM, 0, fd_auth ) == -1 )
-		{
-			cerr << getTime() << "RADIUS-PLUGIN: socketpair call failed for authentication process\n";
-			goto error;
-		}
-		//Accounting process:
-		if ( socketpair ( PF_UNIX, SOCK_DGRAM, 0, fd_acct ) == -1 )
-		{
-			cerr << getTime() << "RADIUS-PLUGIN: socketpair call failed for accounting process\n";
-			goto error;
-		}
+    /** The function is needed by the OpenVpn plugin model. The funtion is called
+     * when OpenVpn starts. In this case here two background process are
+     * started. One for authentication and one for accounting. The communication
+     * between the processes is made via sockets.
+     * You need a background process for accounting, because the interval
+     * in which accounting information is sent to the radius server in undependent
+     * from the main OpenVpn-process, so it is done by another process which schedule
+     * the accounting intervals. This process holds his root rights and it can set and
+     * deletes routes in the system routing table.
+     * The authentication process is a own process, too. So there is clear separation
+     * and it is undependent from the openvpn process.
+     * @param The type of plugin, maybe client_connect, client_disconnect, user_auth_pass_verify...
+     * @param A list of arguments which are set in the configuration file of openvpn in plugin line.
+     * @param The list of enviromental variables, it is created by the OpenVpn-Process.
+     */
 
 
-                
-                
-		//  Fork off the privileged processes.  It will remain privileged
-		//  even after the foreground process drops its privileges.
+    //OPENVPN_EXPORT openvpn_plugin_handle_t
+    //openvpn_plugin_open_v1 ( unsigned int *type_mask, const char *argv[], const char *envp[] )
+    OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v2)(unsigned int *type_mask,
+            const char *argv[],
+            const char *envp[],
+            struct openvpn_plugin_string_list **return_list)
+    {
+        pid_t 					pid;		/**<process number*/
+        int 					fd_auth[2];	/**<An array for the socket pair of the authentication process.*/
+        int 					fd_acct[2];	/**<An array for the socket pair of the accounting process.*/
+        AccountingProcess   	Acct;		/**<The accounting background process object.*/
+        AuthenticationProcess 	Auth; 		/**<The authentication background process object.*/
+        PluginContext *context=NULL; 			/**<The context for this functions.*/
 
 
-		// 	Fork the authentication process
-		pid = fork ();
-		if ( pid )
-		{
-			// Foreground Process (Parent)
-			int status;
-
-			//save the process id
-			context->setAuthPid ( pid );
-
-			// close our copy of child's socket
-			close ( fd_auth[1] );
-
-			/* don't let future subprocesses inherit child socket */
-			if ( fcntl ( fd_auth[0], F_SETFD, FD_CLOEXEC ) < 0 )
-				cerr << getTime() << "RADIUS-PLUGIN: Set FD_CLOEXEC flag on socket file descriptor failed\n";
-
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: Start BACKGROUND Process for authentication with PID " << context->getAuthPid() << ".\n";
-
-			//save the socket number in the context
-			context->authsocketbackgr.setSocket ( fd_auth[0] );
-
-			//wait for background child process to initialize */
-			status = context->authsocketbackgr.recvInt();
-
-			if ( status != RESPONSE_INIT_SUCCEEDED )
-			{
-				//set the socket to -1 if the initialization failed
-				context->authsocketbackgr.setSocket ( -1 );
-			}
-
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: Start AUTH-RADIUS-PLUGIN\n";
-		}
-		else
-		{
-
-			//Background Process
-
-			// close all parent fds except our socket back to parent
-			close_fds_except ( fd_auth[1] );
-
-			// Ignore most signals (the parent will receive them)
-			set_signals ();
-
-			//save the socket number in the context
-			context->authsocketforegr.setSocket ( fd_auth[1] );
-
-			//start the backgroung event loop for accounting
-			Auth.Authentication ( context );
-
-			//close the socket
-			close ( fd_auth[1] );
-
-			//free the context of the background process
-			delete context;
-
-			exit ( 0 );
-			return 0; // NOTREACHED
-		}
-
-		// 	Fork the accounting process
-		pid = fork ();
-		if ( pid )
-		{
-			// Foreground Process (Parent)
-			int status;	//status if the background process
-
-			//save the pid
-			context->setAcctPid ( pid );
-
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: Start BACKGROUND Process for accounting with PID " << context->getAcctPid() << ".\n";
-
-			// close our copy of child's socket */
-			close ( fd_acct[1] );
-
-			/* don't let future subprocesses inherit child socket */
-			if ( fcntl ( fd_acct[0], F_SETFD, FD_CLOEXEC ) < 0 )
-				cerr << getTime() << "RADIUS-PLUGIN: Set FD_CLOEXEC flag on socket file descriptor failed\n";
-
-			//save the socket number in the context
-			context->acctsocketbackgr.setSocket ( fd_acct[0] );
-
-			// wait for background child process to initialize */
-			status = context->acctsocketbackgr.recvInt();
-
-			if ( status != RESPONSE_INIT_SUCCEEDED )
-			{
-				//set the socket to -1 if the initialization failed
-				context->acctsocketbackgr.setSocket ( -1 );
-			}
-
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: Start AUTH-RADIUS-PLUGIN\n";
-		}
-		else
-		{
-
-			//Background Process
-
-			// close all parent fds except our socket back to parent
-			close_fds_except ( fd_acct[1] );
-
-			// Ignore most signals (the parent will receive them)
-			set_signals ();
-
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: Start BACKGROUND Process for accounting\n";
-
-			// save the socket in the context
-			context->acctsocketforegr.setSocket ( fd_acct[1] );
-
-			//start the backgroung event loop for accounting
-			Acct.Accounting ( context );
-
-			//close the socket
-			close ( fd_acct[1] );
-
-			//free the context of the background process
-			delete context;
-			exit ( 0 );
-			return 0; // NOTREACHED
-		}
-
-		//return the context, this is used between the functions
-		//openvpn_plugin_open_v1
-		//openvpn_plugin_func_v1
-		//openvpn_plugin_close_v1
-		return ( openvpn_plugin_handle_t ) context;
-
-	error:
-		//delete the context
-		if ( context )
-			delete ( context );
-		return NULL;
-	}
-
-
-	/** This funtion is called from the OpenVpn process everytime
-	 * a event happens. The function handle the events (plugins)
-	 * AUTH_USER_PASS_VERIFY, CLIENT_CONNECT, CLIENT_DISCONNECT.
-	 * The function reads the information from the envriomental
-	 * variable and sends the relevant information to the
-	 * background processes.
-	 * AUTH_USER_PASS_VERIFY: The user is authenticated by a radius server,
-	 * if it succeeded the background sends back the framed ip, the routes and the acct_interim_interval
-	 * for the user. Than the user is added to the context.
-	 * CLIENT_CONNECT: The user is added to the accounting by
-	 * sending the information to the background process.
-	 * CLIENT_DISCONNECT: The user is deleted from the
-	 * accounting by sending the information to the backgrund process.
-	 * @param The handle which was allocated in the open function.
-	 * @param The type of plugin, maybe client_conect, client_disconnect, auth_user_pass_verify
-	 * @param A list of arguments which are set in the openvpn configuration file.
-	 * @param The list of enviromental variables, it is created by the OpenVpn-Process.
-	 * @return A interger with the status of the funtion (OPENVPN_PLUGIN_FUNC_SUCCESS or OPENVPN_PLUGIN_FUNC_ERROR).
-	 */
-        
-	//OPENVPN_EXPORT int
-	//openvpn_plugin_func_v1 ( openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[] )
-        OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
-        (openvpn_plugin_handle_t handle,
-            const int type,
-              const char *argv[],
-                const char *envp[],
-                  void *per_client_context,
-                    struct openvpn_plugin_string_list **return_list)
-	{
-		
-                
-                //restore the context which was created at the function openvpn_plugin_open_v1
-		PluginContext *context = ( struct PluginContext * ) handle;
+        //Create the context.
+        context=new PluginContext;
+
+        //list for additional arguments
+        struct name_value_list name_value_list;
+
+
+        //There must be one param, the name of the plugin file
+        const int base_parms = 1;
+
+
+
+
+        // Get verbosity level from the environment.
+        const char *verb_string = get_env ( "verb", envp );
+
+        if ( verb_string )
+            context->setVerbosity ( atoi ( verb_string ) );
+
+        if ( DEBUG ( context->getVerbosity() ) )
+            cerr << getTime() << "RADIUS-PLUGIN: Start AUTH-RADIUS-PLUGIN\n";
+
+
+        // Make sure we have one string argument: the .so name.
+        if ( string_array_len ( argv ) < base_parms )
+        {
+            cerr << getTime() << "RADIUS-PLUGIN: no .so name\n";
+            goto error;
+        }
+
+
+        if ( DEBUG ( context->getVerbosity() ) )
+            cerr << getTime() << "RADIUS-PLUGIN: Found "<<  string_array_len ( argv ) << " params.\n";
+
+
+        // See if we have optional name/value pairs for
+        // the plugin, this can only be the config file.
+        // path (default: -c /etc/openvpn/radiusplugin.conf)
+        name_value_list.len = 0;
+        if ( string_array_len ( argv ) > base_parms )
+        {
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: Find params.\n";
 
-                if(context->getStartThread())
+            //just a work around because argv[1] is the filename
+            name_value_list.data[0].name = "-c";
+            name_value_list.data[0].value = argv[1];
+
+            if ( strncmp ( name_value_list.data[0].name,"-c",2 ) ==0 )
+            {
+                //see in ./RadiusClass/error.h for errornumbers
+                //parse the radiusplugin config file
+                cerr << getTime() << "RADIUS-PLUGIN: Configfile name: "<< name_value_list.data[0].value << ".\n";
+                if ( context->radiusconf.parseConfigFile ( name_value_list.data[0].value ) !=0 or context->conf.parseConfigFile ( name_value_list.data[0].value ) !=0 )
                 {
-                  
-		  pthread_cond_init (context->getCondSend(), NULL);
-                  pthread_mutex_init (context->getMutexSend(), NULL);
-                  pthread_cond_init (context->getCondRecv(), NULL);
-                  pthread_mutex_init (context->getMutexRecv(), NULL);
-		  
-		  if(pthread_create(context->getThread(), NULL, &auth_user_pass_verify, (void *) context) != 0) 
-                  {
-                    cerr << getTime() << "RADIUS-PLUGIN: Thread creation failed.\n";
-                    return OPENVPN_PLUGIN_FUNC_ERROR;
-			//goto error;
-                  }
-		  pthread_mutex_lock(context->getMutexRecv());
-                  context->setStartThread(false);
-              
-                } 
-
-		UserPlugin 	*newuser=NULL; 	/**< A context for an new user.*/
-
-		string common_name;			/**<A string for the common_name from the enviroment.*/
-		string untrusted_ip;			/** untrusted_ip for ipv6 support **/
-
-
-		///////////// OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
-		if ( type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && ( context->authsocketbackgr.getSocket() ) >= 0 )
-		{
-
-			if ( DEBUG ( context->getVerbosity() ) )
-			{
-				cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY is called.\n";
-			}
-			//create a new user
-			newuser=new UserPlugin();
-                       
-
-			//allocate the memory, don't care about the value
-			try
-			{
-				if ( get_env ( "username", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: username is not defined\n" );
-				}
-				else if ( get_env ( "password", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: password is not defined\n" );
-				}
-				else if ( get_env ( "untrusted_ip", envp ) ==NULL && get_env ( "untrusted_ip6", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_ip and untrusted_ip6 is not defined\n" );
-				}
-				else if ( get_env ( "common_name", envp ) ==NULL )
-				{
-					if ( context->conf.getClientCertNotRequired() == false )
-					{
-						throw Exception ( "RADIUS-PLUGIN: FOREGROUND: common_name is not defined\n" );
-					}
-				}
-                                else if ( get_env ( "untrusted_port", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_port is not defined\n" );
-				}
+                    cerr << getTime() << "RADIUS-PLUGIN: Bad config file or error in config.\n";
+                    goto error;
+                }
 
-                                
-                                if (get_env ( "auth_control_file", envp ) != NULL)
-                                {
-                                  newuser->setAuthControlFile( get_env ( "auth_control_file", envp ) );
-                                }
-                                
-                    
-				// get username, password, unrusted_ip and common_name from envp string array
-				newuser->setUsername ( get_env ( "username", envp ) );
-				newuser->setPassword ( get_env ( "password", envp ) );
-
-				// it's ipv4
-				if ( get_env ( "untrusted_ip", envp ) !=NULL )
-				{
-					untrusted_ip = get_env ( "untrusted_ip", envp );
-				}
-				// it's ipv6
-				else
-				{
-					untrusted_ip = get_env ( "untrusted_ip6", envp );
-				}
-				newuser->setCallingStationId ( untrusted_ip );
-				//for OpenVPN option client cert not required, common_name is "UNDEF", see status.log
-
-				if ( get_env ( "common_name", envp ) !=NULL )
-				{
-					newuser->setCommonname ( get_env ( "common_name", envp ) );
-				}
-				
-                                //rewrite the username if OpenVPN use the option username-as-comon-name
-				if ( context->conf.getUsernameAsCommonname() == true )
-				{
-					if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Commonname set to Username\n";
-					newuser->setCommonname ( get_env ( "username", envp ) );
-				}
-
-
-				newuser->setUntrustedPort ( get_env ( "untrusted_port", envp ) );
-				newuser->setStatusFileKey(newuser->getCommonname() +string ( "," ) + untrusted_ip + string ( ":" ) + get_env ( "untrusted_port", envp ) );
-                                newuser->setKey(untrusted_ip + string ( ":" ) + get_env ( "untrusted_port", envp ) );
-                                if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Key: " << newuser->getKey() << ".\n";
-                               
-                                if (newuser->getAuthControlFile().length() > 0 && context->conf.getUseAuthControlFile())
+
+            }
+            else
+            {
+                cerr << getTime() << "RADIUS-PLUGIN: Bad argument for plugin.\n";
+                goto error;
+            }
+
+        }
+        else
+        {
+            //if there is no filename, use the default
+            //parse the radiusplugin config file
+            cerr << getTime() << "RADIUS-PLUGIN: Configfile name: /etc/openvpn/radiusplugin.cnf.\n";
+            if ( context->radiusconf.parseConfigFile ( "/etc/openvpn/radiusplugin.cnf" ) !=0 or context->conf.parseConfigFile ( "/etc/openvpn/radiusplugin.cnf" ) !=0 )
+            {
+                cerr << getTime() << "RADIUS-PLUGIN: Bad config file or error in config.\n";
+                goto error;
+            }
+
+        }
+
+
+        // Intercept the --auth-user-pass-verify, --client-connect and --client-disconnect callback.
+        if (context->conf.getAccountingOnly()==false)
+        {
+            *type_mask = OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY ) | OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_CLIENT_CONNECT ) | OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_CLIENT_DISCONNECT );
+        }
+        else //just do the accounting
+        {
+            *type_mask =  OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_CLIENT_CONNECT ) | OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_CLIENT_DISCONNECT );
+        }
+        // Make a socket for foreground and background processes
+        // to communicate.
+        //Authentication process:
+        if ( socketpair ( PF_UNIX, SOCK_DGRAM, 0, fd_auth ) == -1 )
+        {
+            cerr << getTime() << "RADIUS-PLUGIN: socketpair call failed for authentication process\n";
+            goto error;
+        }
+        //Accounting process:
+        if ( socketpair ( PF_UNIX, SOCK_DGRAM, 0, fd_acct ) == -1 )
+        {
+            cerr << getTime() << "RADIUS-PLUGIN: socketpair call failed for accounting process\n";
+            goto error;
+        }
+
+
+
+
+        //  Fork off the privileged processes.  It will remain privileged
+        //  even after the foreground process drops its privileges.
+
+
+        // 	Fork the authentication process
+        pid = fork ();
+        if ( pid )
+        {
+            // Foreground Process (Parent)
+            int status;
+
+            //save the process id
+            context->setAuthPid ( pid );
+
+            // close our copy of child's socket
+            close ( fd_auth[1] );
+
+            /* don't let future subprocesses inherit child socket */
+            if ( fcntl ( fd_auth[0], F_SETFD, FD_CLOEXEC ) < 0 )
+                cerr << getTime() << "RADIUS-PLUGIN: Set FD_CLOEXEC flag on socket file descriptor failed\n";
+
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: Start BACKGROUND Process for authentication with PID " << context->getAuthPid() << ".\n";
+
+            //save the socket number in the context
+            context->authsocketbackgr.setSocket ( fd_auth[0] );
+
+            //wait for background child process to initialize */
+            status = context->authsocketbackgr.recvInt();
+
+            if ( status != RESPONSE_INIT_SUCCEEDED )
+            {
+                //set the socket to -1 if the initialization failed
+                context->authsocketbackgr.setSocket ( -1 );
+            }
+
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: Start AUTH-RADIUS-PLUGIN\n";
+        }
+        else
+        {
+
+            //Background Process
+
+            // close all parent fds except our socket back to parent
+            close_fds_except ( fd_auth[1] );
+
+            // Ignore most signals (the parent will receive them)
+            set_signals ();
+
+            //save the socket number in the context
+            context->authsocketforegr.setSocket ( fd_auth[1] );
+
+            //start the backgroung event loop for accounting
+            Auth.Authentication ( context );
+
+            //close the socket
+            close ( fd_auth[1] );
+
+            //free the context of the background process
+            delete context;
+
+            exit ( 0 );
+            return 0; // NOTREACHED
+        }
+
+        // 	Fork the accounting process
+        pid = fork ();
+        if ( pid )
+        {
+            // Foreground Process (Parent)
+            int status;	//status if the background process
+
+            //save the pid
+            context->setAcctPid ( pid );
+
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: Start BACKGROUND Process for accounting with PID " << context->getAcctPid() << ".\n";
+
+            // close our copy of child's socket */
+            close ( fd_acct[1] );
+
+            /* don't let future subprocesses inherit child socket */
+            if ( fcntl ( fd_acct[0], F_SETFD, FD_CLOEXEC ) < 0 )
+                cerr << getTime() << "RADIUS-PLUGIN: Set FD_CLOEXEC flag on socket file descriptor failed\n";
+
+            //save the socket number in the context
+            context->acctsocketbackgr.setSocket ( fd_acct[0] );
+
+            // wait for background child process to initialize */
+            status = context->acctsocketbackgr.recvInt();
+
+            if ( status != RESPONSE_INIT_SUCCEEDED )
+            {
+                //set the socket to -1 if the initialization failed
+                context->acctsocketbackgr.setSocket ( -1 );
+            }
+
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: Start AUTH-RADIUS-PLUGIN\n";
+        }
+        else
+        {
+
+            //Background Process
+
+            // close all parent fds except our socket back to parent
+            close_fds_except ( fd_acct[1] );
+
+            // Ignore most signals (the parent will receive them)
+            set_signals ();
+
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: Start BACKGROUND Process for accounting\n";
+
+            // save the socket in the context
+            context->acctsocketforegr.setSocket ( fd_acct[1] );
+
+            //start the backgroung event loop for accounting
+            Acct.Accounting ( context );
+
+            //close the socket
+            close ( fd_acct[1] );
+
+            //free the context of the background process
+            delete context;
+            exit ( 0 );
+            return 0; // NOTREACHED
+        }
+
+        //return the context, this is used between the functions
+        //openvpn_plugin_open_v1
+        //openvpn_plugin_func_v1
+        //openvpn_plugin_close_v1
+        return ( openvpn_plugin_handle_t ) context;
+
+error:
+        //delete the context
+        if ( context )
+            delete ( context );
+        return NULL;
+    }
+
+
+    /** This funtion is called from the OpenVpn process everytime
+     * a event happens. The function handle the events (plugins)
+     * AUTH_USER_PASS_VERIFY, CLIENT_CONNECT, CLIENT_DISCONNECT.
+     * The function reads the information from the envriomental
+     * variable and sends the relevant information to the
+     * background processes.
+     * AUTH_USER_PASS_VERIFY: The user is authenticated by a radius server,
+     * if it succeeded the background sends back the framed ip, the routes and the acct_interim_interval
+     * for the user. Than the user is added to the context.
+     * CLIENT_CONNECT: The user is added to the accounting by
+     * sending the information to the background process.
+     * CLIENT_DISCONNECT: The user is deleted from the
+     * accounting by sending the information to the backgrund process.
+     * @param The handle which was allocated in the open function.
+     * @param The type of plugin, maybe client_conect, client_disconnect, auth_user_pass_verify
+     * @param A list of arguments which are set in the openvpn configuration file.
+     * @param The list of enviromental variables, it is created by the OpenVpn-Process.
+     * @return A interger with the status of the funtion (OPENVPN_PLUGIN_FUNC_SUCCESS or OPENVPN_PLUGIN_FUNC_ERROR).
+     */
+
+    //OPENVPN_EXPORT int
+    //openvpn_plugin_func_v1 ( openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[] )
+    OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
+    (openvpn_plugin_handle_t handle,
+     const int type,
+     const char *argv[],
+     const char *envp[],
+     void *per_client_context,
+     struct openvpn_plugin_string_list **return_list)
+    {
+
+
+        //restore the context which was created at the function openvpn_plugin_open_v1
+        PluginContext *context = ( struct PluginContext * ) handle;
+
+        if (context->getStartThread())
+        {
+
+            pthread_cond_init (context->getCondSend(), NULL);
+            pthread_mutex_init (context->getMutexSend(), NULL);
+            pthread_cond_init (context->getCondRecv(), NULL);
+            pthread_mutex_init (context->getMutexRecv(), NULL);
+
+            if (context->conf.getAccountingOnly()==false && pthread_create(context->getThread(), NULL, &auth_user_pass_verify, (void *) context) != 0)
+            {
+                cerr << getTime() << "RADIUS-PLUGIN: Thread creation failed.\n";
+                return OPENVPN_PLUGIN_FUNC_ERROR;
+                //goto error;
+            }
+            pthread_mutex_lock(context->getMutexRecv());
+            context->setStartThread(false);
+            pthread_mutex_unlock(context->getMutexRecv());
+        }
+
+        UserPlugin 	*newuser=NULL; 	/**< A context for an new user.*/
+        UserPlugin 	*tmpuser=NULL; 	/**< A context for an temporary user.*/
+
+        string common_name;			/**<A string for the common_name from the enviroment.*/
+        string untrusted_ip;			/** untrusted_ip for ipv6 support **/
+
+
+        ///////////// OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
+        if ( type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && ( context->authsocketbackgr.getSocket() ) >= 0 )
+        {
+
+            if ( DEBUG ( context->getVerbosity() ) )
+            {
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY is called."<< endl;
+            }
+            //create a new user
+            newuser=new UserPlugin();
+
+
+            //allocate the memory, don't care about the value
+            try
+            {
+                get_user_env(context,type,envp, newuser);
+                 if (newuser->getAuthControlFile().length() > 0 && context->conf.getUseAuthControlFile())
                                 {
                                   pthread_mutex_lock(context->getMutexSend());
                                   context->addNewUser(newuser);
@@ -457,375 +401,300 @@
                                 }
                                 else
                                 {
-                                  pthread_mutex_lock(context->getMutexSend());
+                                  pthread_mutex_lock(context->getMutexRecv());
+				  pthread_mutex_lock(context->getMutexSend());
                                   context->addNewUser(newuser);
                                   pthread_cond_signal( context->getCondSend( ));
                                   pthread_mutex_unlock (context->getMutexSend());
 				  
-                                  pthread_cond_wait( context->getCondRecv(), context->getMutexRecv());
-                                  return context->getResult();
+				  pthread_cond_wait( context->getCondRecv(), context->getMutexRecv());
+				  pthread_mutex_unlock (context->getMutexRecv());
+                                  
+				  return context->getResult();
                                 }
+            }
+            catch ( Exception &e )
+            {
+                cerr << getTime() << e;
+            }
+            catch ( ... )
+            {
+                cerr << getTime() << "Unknown Exception!";
+
+            }
+            return OPENVPN_PLUGIN_FUNC_ERROR;
+            /////////////////////////// CLIENT_CONNECT
+        }
+        if ( type == OPENVPN_PLUGIN_CLIENT_CONNECT && context->acctsocketbackgr.getSocket() >= 0 )
+        {
 
 
-			}
-			catch ( Exception &e )
-			{
-				cerr << getTime() << e;
-			}
-			catch ( ... )
-			{
-				cerr << getTime() << "Unknown Exception!";
-
-			}
-			return OPENVPN_PLUGIN_FUNC_ERROR;
-			/////////////////////////// CLIENT_CONNECT
-		}
-		if ( type == OPENVPN_PLUGIN_CLIENT_CONNECT && context->acctsocketbackgr.getSocket() >= 0 )
-		{
-
-
-			if ( DEBUG ( context->getVerbosity() ) )
-			{
-				cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: OPENVPN_PLUGIN_CLIENT_CONNECT is called.\n";
-			}
-
-			try
-			{
-				if ( get_env ( "untrusted_ip", envp ) ==NULL &&  get_env ( "untrusted_ip6", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_ip and untrusted_ip6 is not defined\n" );
-				}
-				else if ( get_env ( "common_name", envp ) ==NULL )
-				{
-					if ( context->conf.getClientCertNotRequired() == false )
-					{
-						throw Exception ( "RADIUS-PLUGIN: FOREGROUND: common_name is not defined\n" );
-					}
-				}
-				else if ( get_env ( "untrusted_port", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_port is not defined\n" );
-				}
-				else if ( get_env ( "ifconfig_pool_remote_ip", envp ) ==NULL )
-				{	
-				  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: ifconfig_pool_remote_ip is not defined\n" ;
-				}
-				//get username, password and trusted_ip from envp string array
-				//for OpenVPN option client cert not required, common_name is "UNDEF", see status.log
-
-				if ( get_env ( "untrusted_ip", envp ) !=NULL )
-				{
-					untrusted_ip = get_env ( "untrusted_ip", envp );
-				}
-				else
-				{
-					untrusted_ip = get_env ( "untrusted_ip6", envp );
-				}
-
-				if ( get_env ( "common_name", envp ) !=NULL )
-				{
-					common_name=get_env ( "common_name", envp );
-				}
-				else
-				{
-					common_name="UNDEF";
-				}
-				//rewrite the username if OpenVPN use the option username-as-comon-name
-				if ( context->conf.getUsernameAsCommonname() == true )
-				{
-					common_name=get_env ( "username", envp );
-				}
-	
-
-				
-				//find the user in the context, he was added at the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
-				//string key=common_name + string ( "," ) +untrusted_ip+string ( ":" ) + string ( get_env ( "untrusted_port", envp ) );
-                                string key=untrusted_ip+string ( ":" ) + string ( get_env ( "untrusted_port", envp ) );
-                                if ( DEBUG ( context->getVerbosity() ) ){
-                                        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Key: " << key << ".\n";
-				}
-                                newuser=context->findUser(key);
-                                if(newuser == NULL)
-                                {
-                                  
-                                  throw Exception ( "RADIUS-PLUGIN: FOREGROUND: User should be accounted but is unknown, should never happen.\n" );
-                                }
+            if ( DEBUG ( context->getVerbosity() ) )
+            {
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: OPENVPN_PLUGIN_CLIENT_CONNECT is called.\n";
+            }
+
+            try
+            {
+                tmpuser=new UserPlugin();
+                get_user_env(context,type,envp, tmpuser);
+                //find the user in the context, he was added at the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
+                //string key=common_name + string ( "," ) +untrusted_ip+string ( ":" ) + string ( get_env ( "untrusted_port", envp ) );
 
-				//set the assigned ip as Framed-IP-Attribute of the user (see RFC2866, chapter 4.1 for more information)
-				if(get_env ( "ifconfig_pool_remote_ip", envp ) !=NULL)
-				{
-				  newuser->setFramedIp ( string ( get_env ( "ifconfig_pool_remote_ip", envp ) ) );
-				}
-				if ( DEBUG ( context->getVerbosity() ) )
-					cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Set FramedIP to the IP (" << newuser->getFramedIp() << ") OpenVPN assigned to the user " << newuser->getUsername() << "\n";
-				//the user must be there and must be authenticated but not accounted
-				// isAccounted and isAuthenticated is true it is client connect for renegotiation, the user is already in the accounting process
-				if ( newuser!=NULL && newuser->isAccounted() ==false && newuser->isAuthenticated() )
-				{
-					//transform the integers to strings to send them over the socket
-
-					if ( DEBUG ( context->getVerbosity() ) )
-						cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Add user for accounting: username: " << newuser->getUsername() << ", commonname: " << newuser->getCommonname() << "\n";
-
-					//send information to the background process
-					context->acctsocketbackgr.send ( ADD_USER );
-					context->acctsocketbackgr.send ( newuser->getUsername() );
-					context->acctsocketbackgr.send ( newuser->getSessionId() );
-					context->acctsocketbackgr.send ( newuser->getPortnumber() );
-					context->acctsocketbackgr.send ( newuser->getCallingStationId() );
-					context->acctsocketbackgr.send ( newuser->getFramedIp() );
-					context->acctsocketbackgr.send ( newuser->getCommonname() );
-					context->acctsocketbackgr.send ( newuser->getAcctInterimInterval() );
-					context->acctsocketbackgr.send ( newuser->getFramedRoutes() );
-					context->acctsocketbackgr.send ( newuser->getKey() );
-                                        context->acctsocketbackgr.send ( newuser->getStatusFileKey());
-					context->acctsocketbackgr.send ( newuser->getUntrustedPort() );
-					context->acctsocketbackgr.send ( newuser->getVsaBuf(), newuser->getVsaBufLen() );
-					//get the response
-					const int status = context->acctsocketbackgr.recvInt();
-					if ( status == RESPONSE_SUCCEEDED )
-					{
-						newuser->setAccounted ( true );
-
-						if ( DEBUG ( context->getVerbosity() ) )
-							cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Accouting succeeded!\n";
-
-						return OPENVPN_PLUGIN_FUNC_SUCCESS;
-					}
-					else
-					{
-						//free the nasport
-						context->delNasPort ( newuser->getPortnumber() );
-						string error;
-						error="RADIUS-PLUGIN: FOREGROUND: Accounting failed for user:";
-						error+=newuser->getUsername();
-						error+="!\n";
-						//delete user from context
-						context->delUser ( newuser->getKey() );
-						throw Exception ( error );
-					}
-				}
-				else
-				{
-
-					string error;
-					error="RADIUS-PLUGIN: FOREGROUND: No user with this commonname or he is already authenticated: ";
-					error+=common_name;
-					error+="!\n";
-					throw Exception ( error );
-
-				}
-			}
-			catch ( Exception &e )
-			{
-				cerr << getTime() << e;
-			}
-			catch ( ... )
-			{
-				cerr << getTime() << "Unknown Exception!";
-
-			}
-			return OPENVPN_PLUGIN_FUNC_ERROR;
-		}
-
-		///////////////////////// OPENVPN_PLUGIN_CLIENT_DISCONNECT
-
-		if ( type == OPENVPN_PLUGIN_CLIENT_DISCONNECT && context->acctsocketbackgr.getSocket() >= 0 )
-		{
-
-
-			if ( DEBUG ( context->getVerbosity() ) )
-			{
-				cerr << getTime() << "\n\nRADIUS-PLUGIN: FOREGROUND: OPENVPN_PLUGIN_CLIENT_DISCONNECT is called.\n";
-			}
-			try
-			{
-				if ( get_env ( "untrusted_ip", envp ) ==NULL && get_env ( "untrusted_ip6", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_ip and untrusted_ip6 is not defined\n" );
-				}
-				else if ( get_env ( "common_name", envp ) ==NULL )
-				{
-					if ( context->conf.getClientCertNotRequired() == false )
-					{
-						throw Exception ( "RADIUS-PLUGIN: FOREGROUND: common_name is not defined\n" );
-					}
-				}
-				else if ( get_env ( "untrusted_port", envp ) ==NULL )
-				{
-					throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_port is not defined\n" );
-				}
-
-				if ( get_env ( "untrusted_ip", envp ) !=NULL )
-				{
-					untrusted_ip = get_env ( "untrusted_ip", envp );
-				}
-				else
-				{
-					untrusted_ip = get_env ( "untrusted_ip6", envp );
-				}
-
-
-
-				// get common_name from envp string array, if you don't use certificates it is "UNDEF"
-				// get username, password and trusted_ip from envp string array
-				//for OpenVPN option client cert not required, common_name is "UNDEF", see status.log
-				if ( get_env ( "common_name", envp ) !=NULL )
-				{
-					common_name=get_env ( "common_name", envp );
-				}
-				else
-				{
-					common_name="UNDEF";
-				}
-				//rewrite the username if OpenVPN use the option username-as-comon-name
-				if ( context->conf.getUsernameAsCommonname() == true )
-				{
-					common_name=get_env ( "username", envp );
-				}
-
-				//find the user in the context
-				//newuser=context->findUser ( common_name + string ( "," ) + untrusted_ip + string ( ":" ) + string ( get_env ( "untrusted_port", envp ) ) );
-                                newuser=context->findUser ( untrusted_ip + string ( ":" ) + string ( get_env ( "untrusted_port", envp ) ) );
-
-				if ( newuser!=NULL )
-				{
-
-					if ( DEBUG ( context->getVerbosity() ) )
-						cerr << getTime() <<  "RADIUS-PLUGIN: FOREGROUND: Delete user for accounting: commonname: " << newuser->getKey() << "\n";
-
-
-					//send the information to the background process
-					context->acctsocketbackgr.send ( DEL_USER );
-					context->acctsocketbackgr.send ( newuser->getKey() );
-
-					//get the responce
-					const int status = context->acctsocketbackgr.recvInt();
-					if ( status == RESPONSE_SUCCEEDED )
-					{
-						if ( DEBUG ( context->getVerbosity() ) )
-							cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Accouting for user with key" << newuser->getKey()  << " stopped!\n";
-
-						//free the nasport
-						context->delNasPort ( newuser->getPortnumber() );
-
-						//delete user from context
-						context->delUser ( newuser->getKey() );
-						return OPENVPN_PLUGIN_FUNC_SUCCESS;
-					}
-					else
-					{
-						//free the nasport
-						context->delNasPort ( newuser->getPortnumber() );
-
-						//delete user from context
-						context->delUser ( newuser->getKey() );
-						cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Error in ACCT Background Process!\n";
-
-					}
-
-				}
-				else
-				{
-					throw Exception ( "No user with this common_name!\n" );
-
-				}
-			}
-			catch ( Exception &e )
-			{
-				cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND:" << e;
-			}
-			catch ( ... )
-			{
-				cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND:" << "Unknown Exception!\n";
-			}
-
-		}
-
-		return OPENVPN_PLUGIN_FUNC_ERROR;
-	}
-
-
-	/** The function is called when the OpenVpn process exits.
-	 * A exit command is send to the background processes and
-	 * the context is freed which was allocted in the open function.
-	 * @param The handle which was allocated in the open function.
-	 */
-
-	OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1)(openvpn_plugin_handle_t handle)
-	{
-		//restore the context
-		PluginContext *context = ( PluginContext * ) handle;
-
-		if ( DEBUG ( context->getVerbosity() ) )
-			cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: close\n";
-		
-		if ( context->authsocketbackgr.getSocket() >= 0 )
-		{
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: close auth background process\n";
-
-			//tell background process to exit
-			try
-			{
-				context->authsocketbackgr.send ( COMMAND_EXIT );
-			}
-			catch ( Exception &e )
-			{
-				cerr << getTime() << e;
-			}
-
-			// wait for background process to exit
-			if ( context->getAuthPid() > 0 )
-				waitpid ( context->getAuthPid(), NULL, 0 );
-
-		}
-
-		if ( context->acctsocketbackgr.getSocket() >= 0 )
-		{
-			if ( DEBUG ( context->getVerbosity() ) )
-				cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: close acct background process.\n";
-
-			//tell background process to exit
-			try
-			{
-				context->acctsocketbackgr.send ( COMMAND_EXIT );
-			}
-			catch ( Exception &e )
-			{
-				cerr << getTime() << e;
-			}
-                        
-			// wait for background process to exit
-			if ( context->getAcctPid() > 0 )
-				waitpid ( context->getAcctPid(), NULL, 0 );
+                newuser=context->findUser(tmpuser->getKey());
+                if (newuser == NULL)
+                {
+                    if (context->conf.getAccountingOnly()==true) //Authentication part is missing, where this is done else
+                    {
+                        newuser=tmpuser;
+			newuser->setAuthenticated(true); //the plugin does not care about it
+			newuser->setPortnumber ( context->addNasPort() );
+                        newuser->setSessionId ( createSessionId ( newuser ) );
+                        //add the user to the context
+                        context->addUser(newuser);
+                    }
+                    else
+                    {
+                        throw Exception ( "RADIUS-PLUGIN: FOREGROUND: User should be accounted but is unknown, should only occur if accountingonly=true.\n" );
+                    }
+                }
+                else
+		delete(tmpuser);
 
-		}
-		if (context->getStartThread()==false)
+                //set the assigned ip as Framed-IP-Attribute of the user (see RFC2866, chapter 4.1 for more information)
+                if (get_env ( "ifconfig_pool_remote_ip", envp ) !=NULL)
                 {
-                  if ( DEBUG ( context->getVerbosity() ) )
-                      cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Stop auth thread .\n";
-                  //stop the thread
-                  pthread_mutex_lock(context->getMutexSend());
-		  context->setStopThread(true);
-                  pthread_cond_signal( context->getCondSend( ));
-                  pthread_mutex_unlock(context->getMutexSend());
-                  //wait for the thread to exit
-                  pthread_join(*context->getThread(),NULL);
-		  pthread_cond_destroy(context->getCondSend( ));
-		  pthread_cond_destroy(context->getCondRecv( ));
-		  pthread_mutex_destroy(context->getMutexSend());
-		  pthread_mutex_destroy(context->getMutexRecv());
+                    newuser->setFramedIp ( string ( get_env ( "ifconfig_pool_remote_ip", envp ) ) );
+                }
+                if ( DEBUG ( context->getVerbosity() ) )
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Set FramedIP to the IP (" << newuser->getFramedIp() << ") OpenVPN assigned to the user " << newuser->getUsername() << "\n";
+                //the user must be there and must be authenticated but not accounted
+                // isAccounted and isAuthenticated is true it is client connect for renegotiation, the user is already in the accounting process
+                if ( newuser!=NULL && newuser->isAccounted() ==false && newuser->isAuthenticated() )
+                {
+                    //transform the integers to strings to send them over the socket
+
+                    if ( DEBUG ( context->getVerbosity() ) )
+                        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Add user for accounting: username: " << newuser->getUsername() << ", commonname: " << newuser->getCommonname() << "\n";
+
+                    //send information to the background process
+                    context->acctsocketbackgr.send ( ADD_USER );
+                    context->acctsocketbackgr.send ( newuser->getUsername() );
+                    context->acctsocketbackgr.send ( newuser->getSessionId() );
+                    context->acctsocketbackgr.send ( newuser->getPortnumber() );
+                    context->acctsocketbackgr.send ( newuser->getCallingStationId() );
+                    context->acctsocketbackgr.send ( newuser->getFramedIp() );
+                    context->acctsocketbackgr.send ( newuser->getCommonname() );
+                    context->acctsocketbackgr.send ( newuser->getAcctInterimInterval() );
+                    context->acctsocketbackgr.send ( newuser->getFramedRoutes() );
+                    context->acctsocketbackgr.send ( newuser->getKey() );
+                    context->acctsocketbackgr.send ( newuser->getStatusFileKey());
+                    context->acctsocketbackgr.send ( newuser->getUntrustedPort() );
+                    context->acctsocketbackgr.send ( newuser->getVsaBuf(), newuser->getVsaBufLen() );
+                    //get the response
+                    const int status = context->acctsocketbackgr.recvInt();
+                    if ( status == RESPONSE_SUCCEEDED )
+                    {
+                        newuser->setAccounted ( true );
+
+                        if ( DEBUG ( context->getVerbosity() ) )
+                            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Accounting succeeded!\n";
+
+                        return OPENVPN_PLUGIN_FUNC_SUCCESS;
+                    }
+                    else
+                    {
+                        //free the nasport
+                        context->delNasPort ( newuser->getPortnumber() );
+                        string error;
+                        error="RADIUS-PLUGIN: FOREGROUND: Accounting failed for user:";
+                        error+=newuser->getUsername();
+                        error+="!\n";
+                        //delete user from context
+                        context->delUser ( newuser->getKey() );
+                        throw Exception ( error );
+                    }
                 }
                 else
                 {
-                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Auth thread was not started so far.\n";
+
+                    string error;
+                    error="RADIUS-PLUGIN: FOREGROUND: No user with this commonname or he is already authenticated: ";
+                    error+=common_name;
+                    error+="!\n";
+                    throw Exception ( error );
+
                 }
-                
-		delete context;
-                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: DONE.\n";
-                 
-	}
+            }
+            catch ( Exception &e )
+            {
+                cerr << getTime() << e;
+            }
+            catch ( ... )
+            {
+                cerr << getTime() << "Unknown Exception!";
+
+            }
+            return OPENVPN_PLUGIN_FUNC_ERROR;
+        }
+
+        ///////////////////////// OPENVPN_PLUGIN_CLIENT_DISCONNECT
+
+        if ( type == OPENVPN_PLUGIN_CLIENT_DISCONNECT && context->acctsocketbackgr.getSocket() >= 0 )
+        {
+
+
+            if ( DEBUG ( context->getVerbosity() ) )
+            {
+                cerr << getTime() << "\n\nRADIUS-PLUGIN: FOREGROUND: OPENVPN_PLUGIN_CLIENT_DISCONNECT is called.\n";
+            }
+            try
+            {
+                tmpuser=new UserPlugin();
+                get_user_env(context,type,envp, tmpuser);
+                //find the user in the context, he was added at the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
+                //string key=common_name + string ( "," ) +untrusted_ip+string ( ":" ) + string ( get_env ( "untrusted_port", envp ) );
+
+                newuser=context->findUser(tmpuser->getKey());
+		delete(tmpuser);
+                if ( newuser!=NULL )
+                {
+
+                    if ( DEBUG ( context->getVerbosity() ) )
+                        cerr << getTime() <<  "RADIUS-PLUGIN: FOREGROUND: Delete user from accounting: commonname: " << newuser->getKey() << "\n";
+
+
+                    //send the information to the background process
+                    context->acctsocketbackgr.send ( DEL_USER );
+                    context->acctsocketbackgr.send ( newuser->getKey() );
+
+                    //get the responce
+                    const int status = context->acctsocketbackgr.recvInt();
+                    if ( status == RESPONSE_SUCCEEDED )
+                    {
+                        if ( DEBUG ( context->getVerbosity() ) )
+                            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Accounting for user with key" << newuser->getKey()  << " stopped!\n";
+
+                        //free the nasport
+                        context->delNasPort ( newuser->getPortnumber() );
+
+                        //delete user from context
+                        context->delUser ( newuser->getKey() );
+                        return OPENVPN_PLUGIN_FUNC_SUCCESS;
+                    }
+                    else
+                    {
+                        //free the nasport
+                        context->delNasPort ( newuser->getPortnumber() );
+
+                        //delete user from context
+                        context->delUser ( newuser->getKey() );
+                        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Error in ACCT Background Process!\n";
+
+                    }
+
+                }
+                else
+                {
+                    throw Exception ( "No user with this common_name!\n" );
+
+                }
+            }
+            catch ( Exception &e )
+            {
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND:" << e;
+            }
+            catch ( ... )
+            {
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND:" << "Unknown Exception!\n";
+            }
+
+        }
+
+        return OPENVPN_PLUGIN_FUNC_ERROR;
+    }
+
+
+    /** The function is called when the OpenVpn process exits.
+     * A exit command is send to the background processes and
+     * the context is freed which was allocted in the open function.
+     * @param The handle which was allocated in the open function.
+     */
+
+    OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1)(openvpn_plugin_handle_t handle)
+    {
+        //restore the context
+        PluginContext *context = ( PluginContext * ) handle;
+
+        if ( DEBUG ( context->getVerbosity() ) )
+            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: close\n";
+
+        if ( context->authsocketbackgr.getSocket() >= 0 )
+        {
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: close auth background process\n";
+
+            //tell background process to exit
+            try
+            {
+                context->authsocketbackgr.send ( COMMAND_EXIT );
+            }
+            catch ( Exception &e )
+            {
+                cerr << getTime() << e;
+            }
+
+            // wait for background process to exit
+            if ( context->getAuthPid() > 0 )
+                waitpid ( context->getAuthPid(), NULL, 0 );
+
+        }
+
+        if ( context->acctsocketbackgr.getSocket() >= 0 )
+        {
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: close acct background process.\n";
+
+            //tell background process to exit
+            try
+            {
+                context->acctsocketbackgr.send ( COMMAND_EXIT );
+            }
+            catch ( Exception &e )
+            {
+                cerr << getTime() << e;
+            }
+
+            // wait for background process to exit
+            if ( context->getAcctPid() > 0 )
+                waitpid ( context->getAcctPid(), NULL, 0 );
+
+        }
+        if (context->getStartThread()==false)
+        {
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Stop auth thread .\n";
+            //stop the thread
+            pthread_mutex_lock(context->getMutexSend());
+            context->setStopThread(true);
+            pthread_cond_signal( context->getCondSend( ));
+            pthread_mutex_unlock(context->getMutexSend());
+            //wait for the thread to exit
+            pthread_join(*context->getThread(),NULL);
+            pthread_cond_destroy(context->getCondSend( ));
+            pthread_cond_destroy(context->getCondRecv( ));
+            pthread_mutex_destroy(context->getMutexSend());
+            pthread_mutex_destroy(context->getMutexRecv());
+        }
+        else
+        {
+            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Auth thread was not started so far.\n";
+        }
+
+        delete context;
+        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: DONE.\n";
+
+    }
 
 
 }
@@ -842,25 +711,25 @@
  */
 const char * get_env ( const char *name, const char *envp[] )
 {
-	if ( envp )
-	{
-		int i;
-		const int namelen = strlen ( name );
-
-		for ( i = 0; envp[i]; ++i )
-		{
-			//compare the enviromental names
-			if ( !strncmp ( envp[i], name, namelen ) )
-			{
-				//if the varibale is found
-				const char *cp = envp[i] + namelen;
-				//return the value behind the =
-				if ( *cp == '=' )
-					return cp + 1;
-			}
-		}
-	}
-	return NULL;
+    if ( envp )
+    {
+        int i;
+        const int namelen = strlen ( name );
+
+        for ( i = 0; envp[i]; ++i )
+        {
+            //compare the enviromental names
+            if ( !strncmp ( envp[i], name, namelen ) )
+            {
+                //if the varibale is found
+                const char *cp = envp[i] + namelen;
+                //return the value behind the =
+                if ( *cp == '=' )
+                    return cp + 1;
+            }
+        }
+    }
+    return NULL;
 }
 
 
@@ -872,13 +741,13 @@
  */
 int string_array_len ( const char *array[] )
 {
-	int i = 0;
-	if ( array )
-	{
-		while ( array[i] )
-			++i;
-	}
-	return i;
+    int i = 0;
+    if ( array )
+    {
+        while ( array[i] )
+            ++i;
+    }
+    return i;
 }
 
 /** Original function from the openvpn auth-pam plugin.
@@ -894,13 +763,13 @@
  */
 void close_fds_except ( int keep )
 {
-	int i;
-	closelog ();
-	for ( i = 3; i <= 100; ++i )
-	{
-		if ( i != keep )
-			close ( i );
-	}
+    int i;
+    closelog ();
+    for ( i = 3; i <= 100; ++i )
+    {
+        if ( i != keep )
+            close ( i );
+    }
 }
 
 /** Original function from the openvpn auth-pam plugin.
@@ -909,13 +778,13 @@
  */
 void set_signals ( void )
 {
-	signal ( SIGTERM, SIG_DFL );
+    signal ( SIGTERM, SIG_DFL );
 
-	signal ( SIGINT, SIG_IGN );
-	signal ( SIGHUP, SIG_IGN );
-	signal ( SIGUSR1, SIG_IGN );
-	signal ( SIGUSR2, SIG_IGN );
-	signal ( SIGPIPE, SIG_IGN );
+    signal ( SIGINT, SIG_IGN );
+    signal ( SIGHUP, SIG_IGN );
+    signal ( SIGUSR1, SIG_IGN );
+    signal ( SIGUSR2, SIG_IGN );
+    signal ( SIGPIPE, SIG_IGN );
 }
 
 
@@ -929,263 +798,270 @@
  */
 string createSessionId ( UserPlugin * user )
 {
-	unsigned char digest[16];
-	char text[33]; 	//The digest.
-	gcry_md_hd_t  context;						//the hash context
-	int i;
-	time_t rawtime;
-	string strtime;
-	ostringstream portnumber;
-	memset ( digest,0,16 );
-	//build the hash
-	gcry_md_open ( &context, GCRY_MD_MD5, 0 );
-	gcry_md_write ( context, user->getCommonname().c_str(), user->getCommonname().length() );
-	gcry_md_write ( context, user->getCallingStationId().c_str(), user->getCallingStationId().length() );
-	gcry_md_write ( context, user->getUntrustedPort().c_str(), user->getUntrustedPort().length() );
-	gcry_md_write ( context, user->getUntrustedPort().c_str(), user->getUntrustedPort().length() );
-	
-	portnumber << user->getPortnumber();
-	gcry_md_write ( context,portnumber.str().c_str(), portnumber.str().length());
-	time ( &rawtime );
-	strtime=ctime ( &rawtime );
-	gcry_md_write ( context, strtime.c_str(),strtime.length() );
-	memcpy ( digest, gcry_md_read ( context, GCRY_MD_MD5 ), 16 );
-	gcry_md_close ( context );
-
-
-	unsigned int h,l;
-	char *p=text;
-	unsigned char *c=digest;
-	for ( i=0; i<16; i++ )
-	{
-		h = *c / 16;
-		l = *c % 16;
-		c++;
-		*p++ = "01234567890ABCDEF"[h];
-		*p++ = "01234567890ABCDEF"[l];
-	}
-	text[32]='\0';
-	return string ( text );
+    unsigned char digest[16];
+    char text[33]; 	//The digest.
+    gcry_md_hd_t  context;						//the hash context
+    int i;
+    time_t rawtime;
+    string strtime;
+    ostringstream portnumber;
+    memset ( digest,0,16 );
+    //build the hash
+    gcry_md_open ( &context, GCRY_MD_MD5, 0 );
+    gcry_md_write ( context, user->getCommonname().c_str(), user->getCommonname().length() );
+    gcry_md_write ( context, user->getCallingStationId().c_str(), user->getCallingStationId().length() );
+    gcry_md_write ( context, user->getUntrustedPort().c_str(), user->getUntrustedPort().length() );
+    gcry_md_write ( context, user->getUntrustedPort().c_str(), user->getUntrustedPort().length() );
+
+    portnumber << user->getPortnumber();
+    gcry_md_write ( context,portnumber.str().c_str(), portnumber.str().length());
+    time ( &rawtime );
+    strtime=ctime ( &rawtime );
+    gcry_md_write ( context, strtime.c_str(),strtime.length() );
+    memcpy ( digest, gcry_md_read ( context, GCRY_MD_MD5 ), 16 );
+    gcry_md_close ( context );
+
+
+    unsigned int h,l;
+    char *p=text;
+    unsigned char *c=digest;
+    for ( i=0; i<16; i++ )
+    {
+        h = *c / 16;
+        l = *c % 16;
+        c++;
+        *p++ = "01234567890ABCDEF"[h];
+        *p++ = "01234567890ABCDEF"[l];
+    }
+    text[32]='\0';
+    return string ( text );
 }
 
 
-/** The function implements the thread for authentication. If the auth_control_file is specified the thread writes the results in the  
- * auth_control_file, if the file is not specified the thread forward the OPENVPN_PLUGIN_FUNC_SUCCESS or OPENVPN_PLUGIN_FUNC_ERROR 
+/** The function implements the thread for authentication. If the auth_control_file is specified the thread writes the results in the
+ * auth_control_file, if the file is not specified the thread forward the OPENVPN_PLUGIN_FUNC_SUCCESS or OPENVPN_PLUGIN_FUNC_ERROR
  * to the main process.
  * @param _context The context pointer from OpenVPN.
  */
- 
+
 void  * auth_user_pass_verify(void * c)
 {
-        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Auth_user_pass_verify thread started.\n";
-        PluginContext * context = (PluginContext *) c;
-	pthread_mutex_lock(context->getMutexSend());
-        //main thread loop for authentication
-	
-	//ignore signals
-	static sigset_t   signal_mask;
-	sigemptyset (&signal_mask);
-	sigaddset (&signal_mask, SIGINT);
-	sigaddset (&signal_mask, SIGTERM);
-	sigaddset (&signal_mask, SIGHUP);
-	sigaddset (&signal_mask, SIGUSR1);
-	sigaddset (&signal_mask, SIGUSR2);
-	sigaddset (&signal_mask, SIGPIPE);
-        pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
-	
-	
-        while(!context->getStopThread())
-        {
-          if(context->UserWaitingtoAuth()==false)
-          {
-            if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Waiting for new user.\n"; 
+    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Auth_user_pass_verify thread started."<< endl;
+    PluginContext * context = (PluginContext *) c;
+    //pthread_mutex_lock(context->getMutexSend());
+    //main thread loop for authentication
+
+    //ignore signals
+    static sigset_t   signal_mask;
+    sigemptyset (&signal_mask);
+    sigaddset (&signal_mask, SIGINT);
+    sigaddset (&signal_mask, SIGTERM);
+    sigaddset (&signal_mask, SIGHUP);
+    sigaddset (&signal_mask, SIGUSR1);
+    sigaddset (&signal_mask, SIGUSR2);
+    sigaddset (&signal_mask, SIGPIPE);
+    pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
+
+
+    while (!context->getStopThread())
+    {
+        if (context->UserWaitingtoAuth()==false)
+        {
+            if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Waiting for new user." << endl;
+            cout.flush();
+	    pthread_mutex_lock(context->getMutexSend());
             pthread_cond_wait(context->getCondSend(),context->getMutexSend());
-          }
-	  if(context->getStopThread()==true)
-	  { 
-	    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Stop signal received.\n";
-	    break;
-	  }
-          if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: New user from OpenVPN!\n";
-          //is the user already known?
-          UserPlugin	*olduser=NULL;	/**<A context for an already known user.*/
-          UserPlugin	*newuser=NULL;	/**<A context for the new user.*/
-          newuser = context->getNewUser();
-          olduser=context->findUser ( newuser->getKey() );
-         
-          if ( olduser!=NULL )  //probably key renegotiation
-          {
-                  if ( DEBUG ( context->getVerbosity() ) )
-                          cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Renegotiation: username: "<< olduser->getUsername()
-                          << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t olduser ip: " << olduser->getCallingStationId()
-                          << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t olduser port: " << olduser->getUntrustedPort()
-                          << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t olduser FramedIP: " << olduser->getFramedIp()
-                          << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t newuser ip: " << olduser->getCallingStationId()
-                          << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t newuser port: " << olduser->getUntrustedPort()
-                          << "\n";
-                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: isAuthenticated()" <<  olduser->isAuthenticated();
-                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: isAcct()" <<  olduser->isAccounted();
-                  // update password and username, can happen when a new connection is established from the same client with the same port before the timeout in the openvpn server occurs! 
-                  olduser->setPassword(newuser->getPassword());
-                  olduser->setUsername(newuser->getUsername());
-                  olduser->setAuthControlFile(newuser->getAuthControlFile());
-		  //delete the newuser and use the olduser                
-                  delete newuser;
-                  newuser=olduser;
-                  //TODO: for threading check if the user is already accounted (He must be for renegotiation)
-          }
-          else //new user for authentication, no renegotiation
-          {
-                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: New user.\n";
-		  newuser->setPortnumber ( context->addNasPort() );
-                  newuser->setSessionId ( createSessionId ( newuser ) );
-                  //add the user to the context
-                  context->addUser(newuser);
-          }
-  
-          if ( DEBUG ( context->getVerbosity() ) )
-                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: New user: username: "<< newuser->getUsername()  <<", password: *****"
-                  << ", newuser ip: " << newuser->getCallingStationId()
-                  << ", newuser port: " << newuser->getUntrustedPort() << " .\n";
-  
-          //there must be a username
-          if ( newuser->getUsername().size() > 0 )  //&& olduser==NULL)
-          {
-                  //send the informations to the backgorund process
-                  context->authsocketbackgr.send ( COMMAND_VERIFY );
-                  context->authsocketbackgr.send ( newuser->getUsername() );
-                  context->authsocketbackgr.send ( newuser->getPassword() );
-                  context->authsocketbackgr.send ( newuser->getPortnumber() );
-		  context->authsocketbackgr.send ( newuser->getSessionId() );
-                  context->authsocketbackgr.send ( newuser->getCallingStationId() );
-                  context->authsocketbackgr.send ( newuser->getCommonname() );
-                  context->authsocketbackgr.send ( newuser->getFramedIp() );
-  
-                  //get the response
-                  const int status = context->authsocketbackgr.recvInt();
-                  if ( status == RESPONSE_SUCCEEDED )
-                  {
-                          if ( DEBUG ( context->getVerbosity() ) )
-                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Authentication succeeded!\n";
-  
-                          //get the routes from background process
-                          newuser->setFramedRoutes ( context->authsocketbackgr.recvStr() );
-                          if ( DEBUG ( context->getVerbosity() ) )
-                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Received routes for user: "<< newuser->getFramedRoutes() << ".\n";
-                          //get the framed ip
-                          newuser->setFramedIp ( context->authsocketbackgr.recvStr() );
-                          if ( DEBUG ( context->getVerbosity() ) )
-                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Received framed ip for user: "<< newuser->getFramedIp() << ".\n";
-  
-  
-                          // get the interval from the background process
-                          newuser->setAcctInterimInterval ( context->authsocketbackgr.recvInt() );
-                          if ( DEBUG ( context->getVerbosity() ) )
-                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Receive acctinteriminterval " << newuser->getAcctInterimInterval() <<" sec from backgroundprocess.\n";
-  
-                          //clear the buffer if it isn't empty
-                          if ( newuser->getVsaBuf() !=NULL )
-                          {
-                                  delete [] newuser->getVsaBuf();
-                                  newuser->setVsaBuf ( NULL );
-                          }
-                          // get the vendor specific attribute buffer from the background process
-                          context->authsocketbackgr.recvBuf ( newuser );
-  
-                          //add the user to the context
-                          // if the is already in the map, addUser will throw an exception
-                          // only add the user if he it not known already
-                          
-                          if ( newuser->isAuthenticated() ==false )
-                          {
-                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Add user to map.\n";
-                                  //save the success
-                                  newuser->setAuthenticated ( true );
-                          }
-                          else if ( newuser->isAuthenticated() && olduser!=NULL )
-                          {
-                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Don't add the user to the map, it is a rekeying.\n";
-                          }
-                         
-                          if(newuser->getAuthControlFile().length()>0 && context->conf.getUseAuthControlFile())
-                          {
-                            write_auth_control_file(context, newuser->getAuthControlFile(), '1');
-                          }
-                          else
-                          {
-                            pthread_mutex_lock(context->getMutexRecv());
-                            context->setResult(OPENVPN_PLUGIN_FUNC_SUCCESS);
-                            pthread_cond_signal( context->getCondRecv( ));
-                            pthread_mutex_unlock (context->getMutexRecv());
-                          }
-  
-                  }
-                  else //AUTH failed
-                  {
-                          if ( newuser->isAccounted() ) //user is already known, delete him from the accounting
-                          {
-                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Error ar rekeying!\n";
-                                  //error on authenticate user at rekeying -> delete the user!
-                                  //send the information to the background process
-                                  context->acctsocketbackgr.send ( DEL_USER );
-                                  context->acctsocketbackgr.send ( newuser->getKey() );
-  
-                                  //get the responce
-                                  const int status = context->acctsocketbackgr.recvInt();
-                                  if ( status == RESPONSE_SUCCEEDED )
-                                  {
-                                          if ( DEBUG ( context->getVerbosity() ) )
-                                                  cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Accouting for user with key" << newuser->getKey()  << " stopped!\n";
-                                  }
-                                  else
-                                  {
-                                          cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Error in ACCT Background Process!\n";
-                                          cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: User is deleted from the user map!\n";
-                                  }
-                          }
-                          cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Error receiving auth confirmation from background process.\n";
-                          //clean up: nas port, context, memory
-                          context->delNasPort(newuser->getPortnumber());
-                          context->delUser(newuser->getKey());
-
-                          if(newuser->getAuthControlFile().length()>0 && context->conf.getUseAuthControlFile())
-                          {
-                            write_auth_control_file(context, newuser->getAuthControlFile(), '0');
-                          }
-                          else
-                          {
-                            pthread_mutex_lock(context->getMutexRecv());
-                            context->setResult(OPENVPN_PLUGIN_FUNC_ERROR);
-                            pthread_cond_signal( context->getCondRecv( ));
-                            pthread_mutex_unlock (context->getMutexRecv());
-                          }
-                          delete newuser;
-                  }
-          }
-          else
-          {
-              //clean up: nas port, context, memory
-              context->delNasPort(newuser->getPortnumber());
-              context->delUser (newuser->getKey());
-              
-              //return OPENVPN_PLUGIN_FUNC_ERROR;
-              if(newuser->getAuthControlFile().length()>0 && context->conf.getUseAuthControlFile())
-              {
+	    pthread_mutex_unlock(context->getMutexSend());
+        }
+        if (context->getStopThread()==true)
+        {
+            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Stop signal received." << endl;
+            break;
+        }
+        if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: New user from OpenVPN!" << endl;
+        //is the user already known?
+        UserPlugin	*olduser=NULL;	/**<A context for an already known user.*/
+        UserPlugin	*newuser=NULL;	/**<A context for the new user.*/
+        newuser = context->getNewUser();
+        olduser=context->findUser ( newuser->getKey() );
+
+        if ( olduser!=NULL )  //probably key renegotiation
+        {
+            if ( DEBUG ( context->getVerbosity() ) )
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Renegotiation: username: "<< olduser->getUsername()
+                     << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t olduser ip: " << olduser->getCallingStationId()
+                     << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t olduser port: " << olduser->getUntrustedPort()
+                     << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t olduser FramedIP: " << olduser->getFramedIp()
+                     << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t newuser ip: " << olduser->getCallingStationId()
+                     << "\nRADIUS-PLUGIN: FOREGROUND THREAD:\t newuser port: " << olduser->getUntrustedPort()
+                     << "\n";
+            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: isAuthenticated()" <<  olduser->isAuthenticated();
+            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: isAcct()" <<  olduser->isAccounted();
+            // update password and username, can happen when a new connection is established from the same client with the same port before the timeout in the openvpn server occurs!
+            olduser->setPassword(newuser->getPassword());
+            olduser->setUsername(newuser->getUsername());
+            olduser->setAuthControlFile(newuser->getAuthControlFile());
+            //delete the newuser and use the olduser
+            delete newuser;
+            newuser=olduser;
+            //TODO: for threading check if the user is already accounted (He must be for renegotiation)
+        }
+        else //new user for authentication, no renegotiation
+        {
+            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: New user." << endl;
+            newuser->setPortnumber ( context->addNasPort() );
+            newuser->setSessionId ( createSessionId ( newuser ) );
+            //add the user to the context
+            context->addUser(newuser);
+        }
+
+        if ( DEBUG ( context->getVerbosity() ) )
+            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: New user: username: "<< newuser->getUsername()  <<", password: *****"
+                 << ", newuser ip: " << newuser->getCallingStationId()
+                 << ", newuser port: " << newuser->getUntrustedPort() << " ." << endl;
+
+        //there must be a username
+        if ( newuser->getUsername().size() > 0 )  //&& olduser==NULL)
+        {
+            //send the informations to the backgorund process
+            context->authsocketbackgr.send ( COMMAND_VERIFY );
+            context->authsocketbackgr.send ( newuser->getUsername() );
+            context->authsocketbackgr.send ( newuser->getPassword() );
+            context->authsocketbackgr.send ( newuser->getPortnumber() );
+            context->authsocketbackgr.send ( newuser->getSessionId() );
+            context->authsocketbackgr.send ( newuser->getCallingStationId() );
+            context->authsocketbackgr.send ( newuser->getCommonname() );
+            context->authsocketbackgr.send ( newuser->getFramedIp() );
+
+            //get the response
+            const int status = context->authsocketbackgr.recvInt();
+            if ( status == RESPONSE_SUCCEEDED )
+            {
+                if ( DEBUG ( context->getVerbosity() ) )
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Authentication succeeded!" << endl;
+
+                //get the routes from background process
+                newuser->setFramedRoutes ( context->authsocketbackgr.recvStr() );
+                if ( DEBUG ( context->getVerbosity() ) )
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Received routes for user: "<< newuser->getFramedRoutes() << "." << endl;
+                //get the framed ip
+                newuser->setFramedIp ( context->authsocketbackgr.recvStr() );
+                if ( DEBUG ( context->getVerbosity() ) )
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Received framed ip for user: "<< newuser->getFramedIp() << "." << endl;
+
+
+                // get the interval from the background process
+                newuser->setAcctInterimInterval ( context->authsocketbackgr.recvInt() );
+                if ( DEBUG ( context->getVerbosity() ) )
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Receive acctinteriminterval " << newuser->getAcctInterimInterval() <<" sec from backgroundprocess." << endl;
+
+                //clear the buffer if it isn't empty
+                if ( newuser->getVsaBuf() !=NULL )
+                {
+                    delete [] newuser->getVsaBuf();
+                    newuser->setVsaBuf ( NULL );
+                }
+                // get the vendor specific attribute buffer from the background process
+                context->authsocketbackgr.recvBuf ( newuser );
+
+                //add the user to the context
+                // if the is already in the map, addUser will throw an exception
+                // only add the user if he it not known already
+
+                if ( newuser->isAuthenticated() ==false )
+                {
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Add user to map." << endl;
+                    //save the success
+                    newuser->setAuthenticated ( true );
+                }
+                else if ( newuser->isAuthenticated() && olduser!=NULL )
+                {
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Don't add the user to the map, it is a rekeying." << endl;
+                }
+
+                if (newuser->getAuthControlFile().length()>0 && context->conf.getUseAuthControlFile())
+                {
+                    write_auth_control_file(context, newuser->getAuthControlFile(), '1');
+                }
+                else
+                {
+                    pthread_mutex_lock(context->getMutexRecv());
+                    context->setResult(OPENVPN_PLUGIN_FUNC_SUCCESS);
+                    
+		    pthread_cond_signal( context->getCondRecv( ));
+                    pthread_mutex_unlock (context->getMutexRecv());
+
+                }
+
+            }
+            else //AUTH failed
+            {
+                if ( newuser->isAccounted() ) //user is already known, delete him from the accounting
+                {
+                    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Error ar rekeying!" << endl;
+                    //error on authenticate user at rekeying -> delete the user!
+                    //send the information to the background process
+                    context->acctsocketbackgr.send ( DEL_USER );
+                    context->acctsocketbackgr.send ( newuser->getKey() );
+
+                    //get the responce
+                    const int status = context->acctsocketbackgr.recvInt();
+                    if ( status == RESPONSE_SUCCEEDED )
+                    {
+                        if ( DEBUG ( context->getVerbosity() ) )
+                            cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Accounting for user with key" << newuser->getKey()  << " stopped!" << endl;
+                    }
+                    else
+                    {
+                        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Error in ACCT Background Process!" << endl;
+                        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: User is deleted from the user map!" << endl;
+                    }
+                }
+                cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Error receiving auth confirmation from background process." << endl;
+                //clean up: nas port, context, memory
+                context->delNasPort(newuser->getPortnumber());
+                context->delUser(newuser->getKey());
+
+                if (newuser->getAuthControlFile().length()>0 && context->conf.getUseAuthControlFile())
+                {
+                    write_auth_control_file(context, newuser->getAuthControlFile(), '0');
+                }
+                else
+                {
+                    pthread_mutex_lock(context->getMutexRecv());
+                    context->setResult(OPENVPN_PLUGIN_FUNC_ERROR);
+                    pthread_cond_signal( context->getCondRecv( ));
+                    pthread_mutex_unlock (context->getMutexRecv());
+
+                }
+                delete newuser;
+            }
+        }
+        else
+        {
+            //clean up: nas port, context, memory
+            context->delNasPort(newuser->getPortnumber());
+            context->delUser (newuser->getKey());
+
+            //return OPENVPN_PLUGIN_FUNC_ERROR;
+            if (newuser->getAuthControlFile().length()>0 && context->conf.getUseAuthControlFile())
+            {
                 write_auth_control_file(context, newuser->getAuthControlFile(), '0');
-              }
-              else
-              {
+            }
+            else
+            {
                 pthread_mutex_lock(context->getMutexRecv());
                 context->setResult(OPENVPN_PLUGIN_FUNC_ERROR);
+                
                 pthread_cond_signal( context->getCondRecv( ));
-                pthread_mutex_unlock (context->getMutexRecv());
-              }
-              delete newuser;
-          }
-        }
-	pthread_mutex_unlock(context->getMutexSend());
-        cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Thread finished.\n";
-        pthread_exit(NULL);
+		pthread_mutex_unlock (context->getMutexRecv());
+            }
+            delete newuser;
+        }
+    }
+    pthread_mutex_unlock(context->getMutexSend());
+    cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Thread finished.\n";
+    pthread_exit(NULL);
 }
 
 
@@ -1195,19 +1071,19 @@
  */
 void write_auth_control_file(PluginContext * context, string filename, char c)
 {
-  ofstream file;
-  file.open(filename.c_str(),ios::out);
-  if ( DEBUG ( context->getVerbosity() ))
-    cerr << getTime() << "RADIUS-PLUGIN: Write " << c << " to auth_control_file "<< filename << ".\n";
-  if (file.is_open())
-  {
-    file << c;
-    file.close();
-  }
-  else
-  {
-    cerr << getTime() << "RADIUS-PLUGIN: Could not open auth_control_file "<< filename << ".\n";
-  }
+    ofstream file;
+    file.open(filename.c_str(),ios::out);
+    if ( DEBUG ( context->getVerbosity() ))
+        cerr << getTime() << "RADIUS-PLUGIN: Write " << c << " to auth_control_file "<< filename << ".\n";
+    if (file.is_open())
+    {
+        file << c;
+        file.close();
+    }
+    else
+    {
+        cerr << getTime() << "RADIUS-PLUGIN: Could not open auth_control_file "<< filename << ".\n";
+    }
 
 }
 
@@ -1216,11 +1092,91 @@
  */
 string getTime()
 {
-  time_t rawtime;
-  struct tm * timeinfo;
-  time ( &rawtime );
-  timeinfo = localtime ( &rawtime );
-  string t(ctime(&rawtime));
-  t.replace(t.find("\n"),1," ");
-  return t;
+    time_t rawtime;
+    struct tm * timeinfo;
+    time ( &rawtime );
+    timeinfo = localtime ( &rawtime );
+    string t(ctime(&rawtime));
+    t.replace(t.find("\n"),1," ");
+    return t;
+}
+
+void get_user_env(PluginContext * context,const int type,const char * envp[], UserPlugin * user)
+{
+    if ( get_env ( "username", envp ) ==NULL )
+    {
+        if ( context->conf.getAccountingOnly() == false )
+        {
+            throw Exception ( "RADIUS-PLUGIN: FOREGROUND: username is not defined\n" );
+        }
+
+    }
+    else if ( get_env ( "password", envp ) ==NULL )
+    {
+        if ( type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && context->conf.getAccountingOnly() == false  )
+        {
+            throw Exception ( "RADIUS-PLUGIN: FOREGROUND: password is not defined\n" );
+        }
+
+    }
+    else if ( get_env ( "untrusted_ip", envp ) ==NULL && get_env ( "untrusted_ip6", envp ) ==NULL )
+    {
+        throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_ip and untrusted_ip6 is not defined\n" );
+    }
+    else if ( get_env ( "common_name", envp ) ==NULL )
+    {
+        if ( context->conf.getClientCertNotRequired() == false )
+        {
+            throw Exception ( "RADIUS-PLUGIN: FOREGROUND: common_name is not defined\n" );
+        }
+    }
+    else if ( get_env ( "untrusted_port", envp ) ==NULL )
+    {
+        throw Exception ( "RADIUS-PLUGIN: FOREGROUND: untrusted_port is not defined\n" );
+    }
+
+
+    if (get_env ( "auth_control_file", envp ) != NULL)
+    {
+        user->setAuthControlFile( get_env ( "auth_control_file", envp ) );
+    }
+
+
+    // get username, password, unrusted_ip and common_name from envp string array
+    // if the username is not defined and only accounting is used, set the username to the commonname
+    if ( get_env ( "username", envp ) !=NULL )
+        user->setUsername ( get_env ( "username", envp ) );
+    else if (context->conf.getAccountingOnly() == true)
+        user->setUsername ( get_env ( "common_name", envp ) );
+    if ( get_env ( "password", envp ) !=NULL )
+        user->setPassword ( get_env ( "password", envp ) );
+    //rewrite the username if OpenVPN use the option username-as-comon-name
+    if ( context->conf.getUsernameAsCommonname() == true )
+    {
+        if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Commonname set to Username\n";
+        user->setCommonname ( get_env ( "username", envp ) );
+    }
+    if ( get_env ( "common_name", envp ) !=NULL )
+    {
+        user->setCommonname ( get_env ( "common_name", envp ) );
+    }
+
+    string untrusted_ip;
+    // it's ipv4
+    if ( get_env ( "untrusted_ip", envp ) !=NULL )
+    {
+        untrusted_ip = get_env ( "untrusted_ip", envp );
+    }
+    // it's ipv6
+    else
+    {
+        untrusted_ip = get_env ( "untrusted_ip6", envp );
+    }
+    user->setCallingStationId ( untrusted_ip );
+    //for OpenVPN option client cert not required, common_name is "UNDEF", see status.log
+
+    user->setUntrustedPort ( get_env ( "untrusted_port", envp ) );
+    user->setStatusFileKey(user->getCommonname() + string ( "," ) + untrusted_ip + string ( ":" ) + get_env ( "untrusted_port", envp ) );
+    user->setKey(untrusted_ip + string ( ":" ) + get_env ( "untrusted_port", envp ) );
+    if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Key: " << user->getKey() << ".\n";
 }
diff -Nru openvpn-auth-radius-2.1/radiusplugin.h openvpn-auth-radius-2.1a~beta1/radiusplugin.h
--- openvpn-auth-radius-2.1/radiusplugin.h	2009-02-15 15:49:33.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/radiusplugin.h	2010-08-30 10:08:32.000000000 +0000
@@ -107,7 +107,7 @@
 void close_fds_except (int keep);
 void set_signals (void);
 string createSessionId (UserPlugin *);
-
+void get_user_env(PluginContext *, const int type,const char *envp[], UserPlugin *);
 void * auth_user_pass_verify(void *);
 void write_auth_control_file(PluginContext *, string filename, char c);
 string getTime();
diff -Nru openvpn-auth-radius-2.1/UserAcct.cpp openvpn-auth-radius-2.1a~beta1/UserAcct.cpp
--- openvpn-auth-radius-2.1/UserAcct.cpp	2010-04-02 06:18:34.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/UserAcct.cpp	2010-09-02 10:35:23.000000000 +0000
@@ -261,7 +261,7 @@
 	return 1;
 }
 
-/** The method sends an accouting start packet for the user to the radius server.
+/** The method sends an accounting start packet for the user to the radius server.
  *  The following attributes are sent to the radius server:
  * - User_Name, 
  * - Framed_IP_Address,
@@ -384,7 +384,8 @@
 	}
 	
 	//receive the response
-	if (packet.radiusReceive(serverlist)>=0)
+	int ret=packet.radiusReceive(serverlist);
+	if (ret>=0)
 	{
 		//is is a accounting resopnse ?
 		if(packet.getCode()==ACCOUNTING_RESPONSE)
@@ -398,11 +399,15 @@
 		else
 		{
 			if (DEBUG (context->getVerbosity()))
-				cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT:  No response on accounting request.\n";
+				cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT:  Get no ACCOUNTING_RESPONSE-Packet.\n";
 			return 1;
 		}
 		
 	}
+	else
+	{
+	  cerr << getTime() << "RADIUS-PLUGIN: BACKGROUND-ACCT:  Error on receiving radius response, code: " <<  ret << endl;
+	}
 	
 	return 1;
 }
diff -Nru openvpn-auth-radius-2.1/UserAcct.h openvpn-auth-radius-2.1a~beta1/UserAcct.h
--- openvpn-auth-radius-2.1/UserAcct.h	2010-04-02 05:33:03.000000000 +0000
+++ openvpn-auth-radius-2.1a~beta1/UserAcct.h	2010-09-02 10:35:23.000000000 +0000
@@ -33,7 +33,7 @@
 
 /** The class represents a user in the accounting background process. The class is
  * derived from the User class. This class defined additonal attributes
- * for accouting a user.*/
+ * for accounting a user.*/
 
 class UserAcct : public User
 {

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: