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