From 889a50a78bb9cdeb4fba9ce65c2a91b521fa0093 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Fri, 20 Nov 2015 21:54:24 +0300 Subject: [PATCH] Make client-connect function to work asynchronously This commit introcudes asyncronious (or deferred) client-connect function. It works just as auth_user_pass_verify function which can return result using temporary file OpenVPN creates to prevent main OpenVPN thread stall while the user is connecting. You should set useclientconnectdeferfile=true in radiusplugin config file for this function to work. It would fall back to synchronous method if asynchronous method can't be used. Asynchronous client-connect call is not merged upstream as for OpenVPN 2.3.8 and requires patches from Fabian Knittel. --- Config.cpp | 28 +++++ Config.h | 4 + PluginContext.cpp | 52 +++++++- PluginContext.h | 18 +++ UserPlugin.cpp | 13 ++ UserPlugin.h | 4 + radiusplugin.cnf | 13 +- radiusplugin.cpp | 296 ++++++++++++++++++++++++++++++++-------------- radiusplugin.h | 1 + 9 files changed, 340 insertions(+), 89 deletions(-) diff --git a/Config.cpp b/Config.cpp index cddbd20..135cd35 100644 --- a/Config.cpp +++ b/Config.cpp @@ -33,6 +33,7 @@ Config::Config(void) this->clientcertnotrequired=false; this->overwriteccfiles=true; this->useauthcontrolfile=false; + this->useclientconnectdeferfile=false; this->accountingonly=false; this->nonfatalaccounting=false; this->defacctinteriminterval=0; @@ -64,6 +65,7 @@ Config::Config(char * configfile) this->clientcertnotrequired=false; this->overwriteccfiles=true; this->useauthcontrolfile=false; + this->useclientconnectdeferfile=false; this->accountingonly=false; this->nonfatalaccounting=false; this->defacctinteriminterval=0; @@ -158,6 +160,16 @@ int Config::parseConfigFile(const char * configfile) else if (stmp =="false") this->useauthcontrolfile=false; else return BAD_FILE; + } + if (strncmp(line.c_str(),"useclientconnectdeferfile=",26)==0) + { + + string stmp=line.substr(26,line.size()-26); + deletechars(&stmp); + if(stmp == "true") this->useclientconnectdeferfile=true; + else if (stmp =="false") this->useclientconnectdeferfile=false; + else return BAD_FILE; + } if (strncmp(line.c_str(),"accountingonly=",15)==0) { @@ -557,6 +569,22 @@ void Config::setUseAuthControlFile(bool b) this->useauthcontrolfile=b; } +/** Getter method for the clientconnectdeferfile variable. + * @return A bool of clientconnectdeferfile . + */ +bool Config::getUseClientConnectDeferFile(void) +{ + return this->useclientconnectdeferfile; +} + +/** The setter method for the clientconnectdeferfile varibale + * @param overwrite Set to true if the plugin if client-connect control files should be if supported by the OpenVPN version. + */ +void Config::setUseClientConnectDeferFile(bool b) +{ + this->useclientconnectdeferfile=b; +} + bool Config::getAccountingOnly(void) { diff --git a/Config.h b/Config.h index a789d92..693ef3f 100644 --- a/Config.h +++ b/Config.h @@ -52,6 +52,7 @@ class Config string openvpnconfig; /**newusers.push_back(newuser); } -/**The method return the first element in the list of waiting users. +/**The method adds an new user to the user list of users waiting for accounting + * @param newuser A pointer to the user. + */ +void PluginContext::addNewAcctUser(UserPlugin * newuser) +{ + this->newacctusers.push_back(newuser); +} + +/**The method return the first element in the list of waiting for authentication users. */ UserPlugin * PluginContext::getNewUser() { @@ -224,6 +232,18 @@ UserPlugin * PluginContext::getNewUser() } +/**The method return the first element in the list of waiting for accounting users. + */ +UserPlugin * PluginContext::getNewAcctUser() +{ + + + UserPlugin * user = this->newacctusers.front(); + this->newacctusers.pop_front(); + return user; + +} + pthread_cond_t * PluginContext::getCondSend(void ) { return &condsend; @@ -243,12 +263,36 @@ pthread_mutex_t * PluginContext::getMutexRecv(void ) return &mutexrecv; } +pthread_cond_t * PluginContext::getAcctCondSend(void ) +{ + return &acctcondsend; +} +pthread_cond_t * PluginContext::getAcctCondRecv(void ) +{ + return &acctcondrecv; +} + +pthread_mutex_t * PluginContext::getAcctMutexSend(void ) +{ + return &acctmutexsend; +} + +pthread_mutex_t * PluginContext::getAcctMutexRecv(void ) +{ + return &acctmutexrecv; +} + pthread_t * PluginContext::getThread() { return &thread; } +pthread_t * PluginContext::getAcctThread() +{ + return &acctthread; +} + int PluginContext::getResult() { return result; @@ -265,6 +309,12 @@ bool PluginContext::UserWaitingtoAuth() else return false; } +bool PluginContext::UserWaitingtoAcct() +{ + if (this->newacctusers.size()>0) return true; + else return false; +} + bool PluginContext::getStopThread() { diff --git a/PluginContext.h b/PluginContext.h index 2fe4ca8..8a778ce 100755 --- a/PluginContext.h +++ b/PluginContext.h @@ -56,6 +56,7 @@ class PluginContext map users; /**< The user list of the plugin in for the foreground process which are authenticated.*/ list< UserPlugin *> newusers; /**< The user list of the plugin in for the foreground process which are waiting for authentication.*/ + list< UserPlugin *> newacctusers; /**< The user list of the plugin in for the foreground process which are waiting for accounting.*/ list nasportlist; /**< The port list. Every user gets an unipue port on connect. The number is deleted if the user disconnects, a new user can get the number again. This is important for dynamic IP address assignment via the radius server.*/ @@ -67,6 +68,11 @@ class PluginContext pthread_cond_t condrecv; pthread_mutex_t mutexrecv; pthread_t thread; + pthread_cond_t acctcondsend; + pthread_mutex_t acctmutexsend; + pthread_cond_t acctcondrecv; + pthread_mutex_t acctmutexrecv; + pthread_t acctthread; bool stopthread; bool startthread; int result; @@ -113,10 +119,21 @@ class PluginContext pthread_mutex_t * getMutexRecv(void); //void setMutex(pthread_mutex_t); + pthread_cond_t * getAcctCondSend(void); + //void setCond(pthread_cond_t); + pthread_cond_t * getAcctCondRecv(void); + + pthread_mutex_t * getAcctMutexSend(void); + pthread_mutex_t * getAcctMutexRecv(void); + //void setMutex(pthread_mutex_t); + UserPlugin * getNewUser(); + UserPlugin * getNewAcctUser(); void addNewUser(UserPlugin * newuser); + void addNewAcctUser(UserPlugin * newuser); pthread_t * getThread(); + pthread_t * getAcctThread(); int getResult(); void setResult(int); @@ -125,6 +142,7 @@ class PluginContext void setStopThread(bool); bool UserWaitingtoAuth(); + bool UserWaitingtoAcct(); bool getStartThread(); void setStartThread(bool); diff --git a/UserPlugin.cpp b/UserPlugin.cpp index 31b68da..c5a912b 100755 --- a/UserPlugin.cpp +++ b/UserPlugin.cpp @@ -29,6 +29,7 @@ UserPlugin::UserPlugin() : User() this->accounted=false; this->authenticated=false; this->authcontrolfile=""; + this->clientconnectdeferfile=""; } /**The destructor, nothing happens here.*/ @@ -51,6 +52,7 @@ UserPlugin & UserPlugin::operator=(const UserPlugin &u) this->password=u.password; this->untrustedport=u.untrustedport; this->authcontrolfile=u.authcontrolfile; + this->clientconnectdeferfile=u.clientconnectdeferfile; } return *this; @@ -78,6 +80,7 @@ UserPlugin::UserPlugin(const UserPlugin &u) : User(u) this->accounted=u.accounted; this->untrustedport=u.untrustedport; this->authcontrolfile=u.authcontrolfile; + this->clientconnectdeferfile=u.clientconnectdeferfile; } /**The getter method of the password. @@ -149,4 +152,14 @@ void UserPlugin::setAuthControlFile(string file) authcontrolfile=file; } +string UserPlugin::getClientConnectDeferFile(void ) +{ + return clientconnectdeferfile; +} + +void UserPlugin::setClientConnectDeferFile(string file) +{ + clientconnectdeferfile=file; +} + diff --git a/UserPlugin.h b/UserPlugin.h index 3200ed9..01654b7 100755 --- a/UserPlugin.h +++ b/UserPlugin.h @@ -37,6 +37,7 @@ class UserPlugin : public User private: string password; /**= 2.1 rc8) provides them. # The plugin needs write permission to the folder, by default it is the OpenVPN directory (e.g. /etc/openvpm) # The OpenVPN option tmp-dir changes the directory. +# If this option is disabled, OpenVPN would stall while clients are authenticating. # default is false -# useauthcontrolfile=false +useauthcontrolfile=true + +# Allows the plugin to use client-connect deferred files if OpenVPN provides them. +# As for OpenVPN 2.3.8 this functionality is not merged upstream and requires patches from Fabian Knittel. +# The plugin needs write permission to the folder, by default it is the OpenVPN directory (e.g. /etc/openvpn) +# The OpenVPN option tmp-dir changes the directory. +# This option would be disable if OpenVPN doesn't support needed functionality. +# If this option is disabled, OpenVPN would stall while clients are authenticating. +# default is false +useclientconnectdeferfile=true # 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 diff --git a/radiusplugin.cpp b/radiusplugin.cpp index 2cc076f..3cb5827 100755 --- a/radiusplugin.cpp +++ b/radiusplugin.cpp @@ -334,7 +334,7 @@ extern "C" * 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 The type of plugin, maybe client_connect, client_disconnect, auth_user_pass_verify * @param A list of arguments which are set in the openvpn configuration file. * @param The list of environmental variables, it is created by the OpenVpn-Process. * @return An integer with the status of the function (OPENVPN_PLUGIN_FUNC_SUCCESS or OPENVPN_PLUGIN_FUNC_ERROR). @@ -362,10 +362,20 @@ extern "C" pthread_mutex_init (context->getMutexSend(), NULL); pthread_cond_init (context->getCondRecv(), NULL); pthread_mutex_init (context->getMutexRecv(), NULL); + pthread_cond_init (context->getAcctCondSend(), NULL); + pthread_mutex_init (context->getAcctMutexSend(), NULL); + pthread_cond_init (context->getAcctCondRecv(), NULL); + pthread_mutex_init (context->getAcctMutexRecv(), NULL); + if (pthread_create(context->getAcctThread(), NULL, &client_connect, (void *) context) != 0) + { + cerr << getTime() << "RADIUS-PLUGIN: client_connect thread creation failed.\n"; + return OPENVPN_PLUGIN_FUNC_ERROR; + //goto error; + } 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"; + cerr << getTime() << "RADIUS-PLUGIN: auth_user_pass_verify thread creation failed.\n"; return OPENVPN_PLUGIN_FUNC_ERROR; //goto error; } @@ -445,92 +455,26 @@ extern "C" { 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()); - if (newuser == NULL) + if (tmpuser->getClientConnectDeferFile().length() > 0 && context->conf.getUseClientConnectDeferFile()) { - 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 ) ); - if (!newuser->getAcctInterimInterval()) - newuser->setAcctInterimInterval(context->conf.getDefAcctInterimInterval()); - //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" ); - } + pthread_mutex_lock(context->getAcctMutexSend()); + context->addNewAcctUser(tmpuser); + pthread_cond_signal( context->getAcctCondSend( )); + pthread_mutex_unlock (context->getAcctMutexSend()); + return OPENVPN_PLUGIN_FUNC_DEFERRED; } else - delete(tmpuser); - - 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->getDev() ); - context->acctsocketbackgr.send ( newuser->getPortnumber() ); - context->acctsocketbackgr.send ( newuser->getCallingStationId() ); - context->acctsocketbackgr.send ( newuser->getFramedIp() ); - context->acctsocketbackgr.send ( newuser->getFramedIp6() ); - context->acctsocketbackgr.send ( newuser->getCommonname() ); - context->acctsocketbackgr.send ( newuser->getAcctInterimInterval() ); - context->acctsocketbackgr.send ( newuser->getFramedRoutes() ); - context->acctsocketbackgr.send ( newuser->getFramedRoutes6() ); - 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 - { - - string error; - error="RADIUS-PLUGIN: FOREGROUND: No user with this commonname or he is already authenticated: "; - error+=common_name; - error+="!\n"; - throw Exception ( error ); - + pthread_mutex_lock(context->getAcctMutexRecv()); + pthread_mutex_lock(context->getAcctMutexSend()); + context->addNewAcctUser(tmpuser); + pthread_cond_signal( context->getAcctCondSend( )); + pthread_mutex_unlock (context->getAcctMutexSend()); + pthread_cond_wait( context->getAcctCondRecv(), context->getAcctMutexRecv()); + pthread_mutex_unlock (context->getAcctMutexRecv()); + + return context->getResult(); } } catch ( Exception &e ) @@ -698,25 +642,32 @@ extern "C" if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Stop auth thread .\n"; - //stop the thread + //stop the threads pthread_mutex_lock(context->getMutexSend()); context->setStopThread(true); pthread_cond_signal( context->getCondSend( )); pthread_mutex_unlock(context->getMutexSend()); + pthread_mutex_lock(context->getAcctMutexSend()); + pthread_cond_signal( context->getAcctCondSend( )); + pthread_mutex_unlock(context->getAcctMutexSend()); //wait for the thread to exit if (context->conf.getAccountingOnly()==false) pthread_join(*context->getThread(),NULL); + pthread_join(*context->getAcctThread(),NULL); pthread_cond_destroy(context->getCondSend( )); pthread_cond_destroy(context->getCondRecv( )); pthread_mutex_destroy(context->getMutexSend()); pthread_mutex_destroy(context->getMutexRecv()); - + pthread_cond_destroy(context->getAcctCondSend( )); + pthread_cond_destroy(context->getAcctCondRecv( )); + pthread_mutex_destroy(context->getAcctMutexSend()); + pthread_mutex_destroy(context->getAcctMutexRecv()); } else { - cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Auth thread was not started so far.\n"; + cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND: Auth and Acct threads were not started so far.\n"; } delete context; @@ -1113,6 +1064,175 @@ void * auth_user_pass_verify(void * c) pthread_exit(NULL); } +/** The function implements the thread for accounting. If the client_connect_deferred_file is specified the thread writes the results in the + * client_connect_deferred_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 * client_connect(void * c) +{ + cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: client_connect thread started."<< endl; + //PluginContext * context = (PluginContext *) c; + 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->UserWaitingtoAcct()==false) + { + if ( DEBUG ( context->getVerbosity() ) ) cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Waiting for new accounting user." << endl; + cout.flush(); + pthread_mutex_lock(context->getAcctMutexSend()); + pthread_cond_wait(context->getAcctCondSend(),context->getAcctMutexSend()); + pthread_mutex_unlock(context->getAcctMutexSend()); + } + if (context->getStopThread()==true) + { + cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Stop signal received." << endl; + break; + } + + //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 ) ); + + UserPlugin *newuser=NULL; /**getNewAcctUser(); + 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 ) ); + if (!newuser->getAcctInterimInterval()) + newuser->setAcctInterimInterval(context->conf.getDefAcctInterimInterval()); + //add the user to the context + context->addUser(newuser); + } + else + { + cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: User should be accounted but is unknown, should only occur if accountingonly=true.\n"; + pthread_mutex_lock(context->getAcctMutexRecv()); + context->setResult(OPENVPN_PLUGIN_FUNC_ERROR); + + pthread_cond_signal( context->getAcctCondRecv( )); + pthread_mutex_unlock (context->getAcctMutexRecv()); + } + } + else + delete(tmpuser); + + if ( DEBUG ( context->getVerbosity() ) ) + cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: 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 THREAD: 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->getDev() ); + context->acctsocketbackgr.send ( newuser->getPortnumber() ); + context->acctsocketbackgr.send ( newuser->getCallingStationId() ); + context->acctsocketbackgr.send ( newuser->getFramedIp() ); + context->acctsocketbackgr.send ( newuser->getFramedIp6() ); + context->acctsocketbackgr.send ( newuser->getCommonname() ); + context->acctsocketbackgr.send ( newuser->getAcctInterimInterval() ); + context->acctsocketbackgr.send ( newuser->getFramedRoutes() ); + context->acctsocketbackgr.send ( newuser->getFramedRoutes6() ); + 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 THREAD: Accounting succeeded!\n"; + + if (newuser->getClientConnectDeferFile().length()>0 && context->conf.getUseClientConnectDeferFile()) + { + write_control_file(context, newuser->getClientConnectDeferFile(), '1'); + } + else + { + pthread_mutex_lock(context->getAcctMutexRecv()); + context->setResult(OPENVPN_PLUGIN_FUNC_SUCCESS); + + pthread_cond_signal( context->getAcctCondRecv( )); + pthread_mutex_unlock (context->getAcctMutexRecv()); + + } + + //return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + else + { + //free the nasport + context->delNasPort ( newuser->getPortnumber() ); + string error; + error="RADIUS-PLUGIN: FOREGROUND THREAD: Accounting failed for user:"; + error+=newuser->getUsername(); + error+="!\n"; + cerr << getTime() << error; + //delete user from context + context->delUser ( newuser->getKey() ); + + if (newuser->getClientConnectDeferFile().length()>0 && context->conf.getUseClientConnectDeferFile()) + { + write_control_file(context, newuser->getClientConnectDeferFile(), '0'); + + } + pthread_mutex_lock(context->getAcctMutexRecv()); + context->setResult(OPENVPN_PLUGIN_FUNC_ERROR); + pthread_cond_signal( context->getAcctCondRecv( )); + pthread_mutex_unlock (context->getAcctMutexRecv()); + + } + } + else + { + cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: No user with this commonname or he is already authenticated\n"; + pthread_mutex_lock(context->getAcctMutexRecv()); + context->setResult(OPENVPN_PLUGIN_FUNC_ERROR); + + pthread_cond_signal( context->getAcctCondRecv( )); + pthread_mutex_unlock (context->getAcctMutexRecv()); + + } + } + pthread_mutex_unlock(context->getAcctMutexRecv()); + pthread_mutex_unlock(context->getAcctMutexSend()); + cerr << getTime() << "RADIUS-PLUGIN: FOREGROUND THREAD: Thread finished.\n"; + pthread_exit(NULL); + +} + /** Writes the result of the authentication or accounting to the auth or client-connect control file (0: failure, 1: success). * @param filename The control file. @@ -1193,6 +1313,10 @@ void get_user_env(PluginContext * context,const int type,const char * envp[], Us user->setAuthControlFile( get_env ( "auth_control_file", envp ) ); } + if (get_env ( "client_connect_deferred_file", envp ) != NULL) + { + user->setClientConnectDeferFile( get_env ( "client_connect_deferred_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 diff --git a/radiusplugin.h b/radiusplugin.h index 7096931..1e63c86 100755 --- a/radiusplugin.h +++ b/radiusplugin.h @@ -109,6 +109,7 @@ 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 * client_connect(void *); void write_control_file(PluginContext *, string filename, char c); string getTime();