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