12#include <asio/placeholders.hpp>
20#include <openssl/ssl.h>
24#define RESIPROCATE_SUBSYSTEM ReTurnSubsystem::RETURN
27#define SOFTWARE_STRING "reTURNServer " PACKAGE_VERSION " (RFC5389)"
29#define SOFTWARE_STRING "reTURNServer (RFC5389)"
35#ifdef BOOST_ASIO_HAS_STD_CHRONO
36using namespace std::chrono;
39using namespace std::chrono;
46 mPadSoftwareName(true),
50 mTurnAddress(
asio::ip::make_address(
"0.0.0.0")),
51 mTurnV6Address(
asio::ip::make_address(
"::0")),
52 mAltStunAddress(
asio::ip::make_address(
"0.0.0.0")),
53 mAuthenticationRealm(
"reTurn"),
54 mUserDatabaseCheckInterval(60),
56 mAllocationPortRangeMin(49152),
57 mAllocationPortRangeMax(65535),
58 mDefaultAllocationLifetime(600),
59 mMaxAllocationLifetime(3600),
60 mMaxAllocationsPerUser(0),
61 mTlsServerCertificateFilename(
"server.pem"),
62 mTlsServerPrivateKeyFilename(
""),
63 mTlsTempDhFilename(
"dh2048.pem"),
64 mTlsPrivateKeyPassword(
""),
65 mTlsHandshakeTimeout(30),
66 mTcpConnectionIdleTimeout(60),
67 mMaxTcpConnectionsPerIp(0),
70 mOpenSSLCTXSetOptions(SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION),
72 mOpenSSLCTXSetOptions(0),
74 mOpenSSLCTXClearOptions(0),
75 mUsersDatabaseFilename(
""),
76 mUserDatabaseHashedPasswords(false),
113 for (
const char* name : {
"OpenSSLCTXSetOptions",
"OpenSSLCTXClearOptions" })
115 std::set<Data> values;
120 for (
const Data& value : values)
149 throw ConfigParse::Exception(
"Missing user database option! Expected \"UserDatabaseFile = file location\".", __FILE__, __LINE__);
172 mRealmUsersAuthenticaionCredentials[std::make_pair(username, realm)] = newUser.
getHa1();
174 realmUsers.insert(pair<resip::Data,UserAuthData>(username, newUser));
180 std::ifstream accountDatabaseFile(accountDatabaseFilename.
c_str());
182 int lineNbr = 0, userCount = 0;
183 if(!accountDatabaseFile)
189 mRealmUsersAuthenticaionCredentials.clear();
191 while(std::getline(accountDatabaseFile, sline))
216 const char * anchor = pb.
position();
222 ErrLog(<<
"Missing or invalid credentials at line " << lineNbr);
226 pb.
data(username, anchor);
240 ErrLog(<<
"Missing or invalid credentials at line " << lineNbr);
244 pb.
data(password, anchor);
258 ErrLog(<<
"Missing or invalid credentials at line " << lineNbr);
262 pb.
data(realm, anchor);
276 pb.
data(state, anchor);
279 if (state.
size() != 0)
281 if(state ==
"authorized")
285 else if(state ==
"restricted")
289 else if(state ==
"refused")
295 ErrLog(<<
"Invalid state value at line " << lineNbr <<
", state= " << state);
301 ErrLog(<<
"Missing state value at line " << lineNbr);
308 addUser(username, password, realm);
310 ErrLog(<<
"Exception adding user: " << username <<
", cause: " << ex <<
", skipping record");
316 InfoLog(<<
"Processed " << userCount <<
" user(s) from " << lineNbr <<
" line(s) in " << accountDatabaseFilename);
317 accountDatabaseFile.close();
328 std::cerr <<
"Command line format is:" << std::endl;
329 std::cerr <<
" " <<
removePath(argv[0]) <<
" [<ConfigFilename>] [--<ConfigValueName>=<ConfigValue>] [--<ConfigValueName>=<ConfigValue>] ..." << std::endl;
330 std::cerr <<
"Sample Command lines:" << std::endl;
331 std::cerr <<
" " <<
removePath(argv[0]) <<
" reTurnServer.config --LogLevel=INFO" << std::endl;
338 return getUser(username, realm).get() != NULL;
345 std::map<RealmUserPair, resip::Data>::const_iterator it = mRealmUsersAuthenticaionCredentials.find(std::make_pair(username, realm));
346 if(it != mRealmUsersAuthenticaionCredentials.end())
356std::unique_ptr<UserAuthData>
360 std::unique_ptr<UserAuthData> ret;
361 std::map<resip::Data,RealmUsers>::const_iterator it = mUsers.find(realm);
362 if(it == mUsers.end())
366 RealmUsers::const_iterator it2 = realmUsers.find(userName);
367 if(it2 == realmUsers.end())
370 return std::unique_ptr<UserAuthData>(
new UserAuthData(it2->second));
373bool ReTurnUserFileScanner::mHup =
false;
376 : mLoadedTime(time(0)),
377 mReTurnConfig(reTurnConfig),
379 mNextFileCheck(mLoadedTime + reTurnConfig.mUserDatabaseCheckInterval),
380 mTimer(ioService, seconds(mLoopInterval))
387 signal(SIGHUP, onSignal);
394 int timerInterval = mLoopInterval;
396 if(timerInterval > 0)
398 mTimer.expires_after(seconds(timerInterval));
399 mTimer.async_wait(std::bind(&ReTurnUserFileScanner::timeout,
this, std::placeholders::_1));
404ReTurnUserFileScanner::hasUserFileChanged()
406 StackLog(<<
"checking user database freshness");
408 time_t latestFileTS = 0;
410 StackLog(<<
"not yet implemented on Windows");
412 struct stat user_stat;
416 latestFileTS = user_stat.st_mtime;
424 return latestFileTS > mLoadedTime;
428ReTurnUserFileScanner::timeout(
const asio::error_code& e)
430 bool mustReload = mHup;
434 time_t now = time(0);
435 if(now >= mNextFileCheck)
437 mustReload = hasUserFileChanged();
444 InfoLog(<<
"change in user database detected, reloading...");
449 InfoLog(<<
"user database reload completed");
450 mLoadedTime = time(0);
453 catch (ReTurnConfig::Exception&)
468ReTurnUserFileScanner::onSignal(
int signum)
473 InfoLog(<<
"HUP signal received, scheduling a users.txt reload");
480 WarningLog(<<
"received unexpected signal number " << signum);
#define WarningLog(args_)
unsigned short mAllocationPortRangeMax
long mOpenSSLCTXClearOptions
std::unique_ptr< UserAuthData > getUser(const resip::Data &userName, const resip::Data &realm) const
unsigned long mMaxTcpConnectionsPerIp
unsigned short mAltStunPort
asio::ip::address mAltStunAddress
unsigned long mTlsHandshakeTimeout
int mUserDatabaseCheckInterval
resip::Data mTlsTempDhFilename
bool isUserNameValid(const resip::Data &username, const resip::Data &realm) const
void authParse(const resip::Data &accountDatabaseFilename)
unsigned short mTlsTurnPort
resip::Data mSoftwareName
resip::Data mUsersDatabaseFilename
resip::Data mTlsPrivateKeyPassword
asio::ip::address mTurnAddress
void addUser(const resip::Data &username, const resip::Data &password, const resip::Data &realm)
unsigned short mAllocationPortRangeMin
resip::Data mAuthenticationRealm
long mOpenSSLCTXSetOptions
unsigned long mDefaultAllocationLifetime
resip::Data mTlsServerCertificateFilename
resip::RWMutex mUserDataMutex
void printHelpText(int argc, char **argv)
bool mUserDatabaseHashedPasswords
unsigned long mMaxAllocationsPerUser
unsigned long mTcpConnectionIdleTimeout
virtual void parseConfig(int argc, char **argv, const resip::Data &defaultConfigFilename)
unsigned long mMaxAllocationLifetime
resip::Data getHa1ForUsername(const resip::Data &username, const resip::Data &realm) const
unsigned long mNonceLifetime
resip::Data mTlsServerPrivateKeyFilename
asio::ip::address mTurnV6Address
ReTurnUserFileScanner(asio::io_context &ioService, ReTurnConfig &reTurnConfig)
static UserAuthData createFromHex(const resip::Data &userName, const resip::Data &realm, const resip::Data &ha1Hex)
static UserAuthData createFromPassword(const resip::Data &userName, const resip::Data &realm, const resip::Data &password)
unsigned short getConfigUnsignedShort(const resip::Data &name, int defaultValue) const
bool AddBasePathIfRequired(Data &filename) const
virtual void parseConfig(int argc, char **argv, const resip::Data &defaultConfigFilename)
resip::Data removePath(const resip::Data &fileAndPath) const
resip::Data getConfigData(const resip::Data &name, const resip::Data &defaultValue, bool useDefaultIfEmpty=false) const
bool getConfigValue(const resip::Data &name, resip::Data &value) const
unsigned long getConfigUnsignedLong(const resip::Data &name, unsigned long defaultValue) const
bool getConfigBool(const resip::Data &name, bool defaultValue) const
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
static const Data Empty
Constant that represents a zero-length data.
const char * c_str() const
Returns a null-terminated string representing.
Data & lowercase()
Converts this Data to lowercase.
size_type size() const noexcept
Returns the number of bytes in this Data.
static void reset()
Frees logger stream.
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipWhitespace()
CurrentPosition skipToChar(char c)
CurrentPosition position() const
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
std::map< resip::Data, reTurn::UserAuthData > RealmUsers
dcm! – add UnusedChecking(_enum) below;
long parseOpenSSLCTXOption(const Data &optionName)
Converts an OpenSSL option name (eg.