2019-07-17 19:37:18 +02:00
# define XMALLOC undefined_malloc /* fix jemalloc and tomcrypt */
# define XCALLOC undefined_calloc
# define XFREE undefined_free
# define XREALLOC undefined_realloc
# include <netdb.h>
# include "src/weblist/WebListManager.h"
# include <log/LogUtils.h>
# include "InstanceHandler.h"
# include "src/client/InternalClient.h"
# include "src/server/QueryServer.h"
2020-05-03 14:06:34 +02:00
# include "src/server/file/LocalFileServer.h"
2019-07-17 19:37:18 +02:00
# include "SignalHandler.h"
2019-08-25 23:55:55 +02:00
# include "src/manager/PermissionNameMapper.h"
2019-07-17 19:37:18 +02:00
# include <ThreadPool/Timer.h>
# include "ShutdownHelper.h"
# include <sys/utsname.h>
# include "build.h"
# include <misc/digest.h>
# include <misc/base64.h>
2019-11-22 20:51:00 +01:00
# include <misc/hex.h>
2019-07-17 19:37:18 +02:00
# include <misc/rnd.h>
2019-09-14 12:06:48 +02:00
# include <misc/strobf.h>
2019-07-17 19:37:18 +02:00
# include <jemalloc/jemalloc.h>
2020-03-02 13:33:57 +01:00
# include <protocol/buffers.h>
2019-07-17 19:37:18 +02:00
# ifndef _POSIX_SOURCE
2020-01-24 02:57:58 +01:00
# define _POSIX_SOURCE
2019-07-17 19:37:18 +02:00
# endif
# include <unistd.h>
# undef _POSIX_SOURCE
using namespace std ;
using namespace std : : chrono ;
using namespace ts ;
using namespace ts : : server ;
# define INSTANCE_TICK_NAME "instance"
extern bool mainThreadActive ;
InstanceHandler : : InstanceHandler ( SqlDataManager * sql ) : sql ( sql ) {
2020-01-24 02:57:58 +01:00
serverInstance = this ;
this - > tick_manager = make_shared < threads : : Scheduler > ( config : : threads : : ticking , " tick task " ) ;
2020-04-08 13:01:41 +02:00
this - > statistics = make_shared < stats : : ConnectionStatistics > ( nullptr ) ;
2019-07-17 19:37:18 +02:00
2020-02-28 11:24:07 +01:00
std : : string error_message { } ;
this - > license_service_ = std : : make_shared < license : : LicenseService > ( ) ;
if ( ! this - > license_service_ - > initialize ( error_message ) ) {
logCritical ( LOG_INSTANCE , strobf ( " Failed to the license service: {} " ) . string ( ) , error_message ) ;
}
2020-01-24 02:57:58 +01:00
this - > dbHelper = new DatabaseHelper ( this - > getSql ( ) ) ;
2019-07-17 19:37:18 +02:00
this - > _properties = new Properties ( ) ;
2020-01-24 02:57:58 +01:00
this - > _properties - > register_property_type < property : : InstanceProperties > ( ) ;
this - > properties ( ) [ property : : SERVERINSTANCE_FILETRANSFER_PORT ] = ts : : config : : binding : : DefaultFilePort ;
this - > properties ( ) [ property : : SERVERINSTANCE_FILETRANSFER_HOST ] = ts : : config : : binding : : DefaultFileHost ;
this - > properties ( ) [ property : : SERVERINSTANCE_QUERY_PORT ] = ts : : config : : binding : : DefaultQueryPort ;
this - > properties ( ) [ property : : SERVERINSTANCE_QUERY_HOST ] = ts : : config : : binding : : DefaultQueryHost ;
2019-07-17 19:37:18 +02:00
auto result = sql : : command ( this - > getSql ( ) , " SELECT * FROM `properties` WHERE `id` = :id AND `type` = :type AND `serverId` = :serverId " , variable { " :id " , 0 } , variable { " :serverId " , 0 } , variable { " :type " , property : : PropertyType : : PROP_TYPE_INSTANCE } )
. query ( [ ] ( InstanceHandler * instance , int length , char * * values , char * * columns ) {
string key , value ;
for ( int index = 0 ; index < length ; index + + ) {
if ( strcmp ( columns [ index ] , " key " ) = = 0 ) {
key = values [ index ] ;
} else if ( strcmp ( columns [ index ] , " value " ) = = 0 ) {
value = values [ index ] = = nullptr ? " " : values [ index ] ;
}
}
2020-04-08 13:01:41 +02:00
const auto & info = property : : find < property : : InstanceProperties > ( key ) ;
if ( info = = property : : SERVERINSTANCE_UNDEFINED ) {
2020-01-24 02:57:58 +01:00
logError ( 0 , " Got an unknown instance property " + key ) ;
return 0 ;
}
2019-07-17 19:37:18 +02:00
auto prop = instance - > properties ( ) [ info ] ;
prop = value ;
prop . setDbReference ( true ) ;
prop . setModified ( false ) ;
return 0 ;
} , this ) ;
if ( ! result ) cerr < < result < < endl ;
this - > _properties - > registerNotifyHandler ( [ & ] ( Property & prop ) {
if ( ( prop . type ( ) . flags & property : : FLAG_SAVE ) = = 0 ) {
prop . setModified ( false ) ;
return ;
}
string sqlQuery ;
if ( prop . hasDbReference ( ) )
sqlQuery = " UPDATE `properties` SET `value` = :value WHERE `serverId` = :sid AND `type` = :type AND `id` = :id AND `key` = :key " ;
else {
prop . setDbReference ( true ) ;
sqlQuery = " INSERT INTO `properties` (`serverId`, `type`, `id`, `key`, `value`) VALUES (:sid, :type, :id, :key, :value) " ;
}
sql : : command ( this - > getSql ( ) , sqlQuery , variable { " :sid " , 0 } , variable { " :type " , property : : PropertyType : : PROP_TYPE_INSTANCE } , variable { " :id " , 0 } , variable { " :key " , prop . type ( ) . name } , variable { " :value " , prop . value ( ) } )
. executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , sql : : result { 1 , " future failed " } ) ;
} ) ;
2020-01-24 02:57:58 +01:00
this - > properties ( ) [ property : : SERVERINSTANCE_DATABASE_VERSION ] = this - > sql - > get_database_version ( ) ;
this - > properties ( ) [ property : : SERVERINSTANCE_PERMISSIONS_VERSION ] = this - > sql - > get_permissions_version ( ) ;
2019-07-17 19:37:18 +02:00
globalServerAdmin = std : : make_shared < ts : : server : : InternalClient > ( this - > getSql ( ) , nullptr , " serveradmin " , true ) ;
static_pointer_cast < ts : : server : : InternalClient > ( globalServerAdmin ) - > setSharedLock ( globalServerAdmin ) ;
ts : : server : : DatabaseHelper : : assignDatabaseId ( this - > getSql ( ) , 0 , globalServerAdmin ) ;
2020-01-24 02:57:58 +01:00
this - > _musicRoot = std : : make_shared < InternalClient > ( this - > getSql ( ) , nullptr , " Music Manager " , false ) ;
static_pointer_cast < InternalClient > ( this - > _musicRoot ) - > setSharedLock ( this - > _musicRoot ) ;
{
this - > groupManager = std : : make_shared < GroupManager > ( nullptr , this - > getSql ( ) ) ;
this - > groupManager - > loadGroupFormDatabase ( ) ;
if ( this - > groupManager - > availableServerGroups ( false ) . empty ( ) ) {
if ( ! this - > setupDefaultGroups ( ) ) {
logCritical ( LOG_INSTANCE , " Could not setup server instance! Stopping... " ) ;
mainThreadActive = false ;
return ;
}
}
debugMessage ( LOG_INSTANCE , " Instance admin group id " + to_string ( this - > properties ( ) [ property : : SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP ] . as < GroupId > ( ) ) ) ;
auto instance_server_admin = this - > groupManager - > findGroup ( this - > properties ( ) [ property : : SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP ] . as < GroupId > ( ) ) ;
if ( ! instance_server_admin ) {
instance_server_admin = this - > groupManager - > availableServerGroups ( false ) . front ( ) ;
logCritical ( LOG_INSTANCE , " Missing instance server admin group! Using first available ( " + ( instance_server_admin ? instance_server_admin - > name ( ) : " nil " ) + " ) " ) ;
}
if ( this - > groupManager - > listGroupAssignments ( this - > globalServerAdmin - > getClientDatabaseId ( ) ) . empty ( ) )
this - > groupManager - > addServerGroup ( this - > globalServerAdmin - > getClientDatabaseId ( ) , instance_server_admin ) ;
debugMessage ( LOG_INSTANCE , " Server guest group id " + to_string ( this - > properties ( ) [ property : : SERVERINSTANCE_GUEST_SERVERQUERY_GROUP ] . as < GroupId > ( ) ) ) ;
auto instance_server_guest = this - > groupManager - > findGroup ( this - > properties ( ) [ property : : SERVERINSTANCE_GUEST_SERVERQUERY_GROUP ] . as_save < GroupId > ( ) ) ;
if ( ! instance_server_guest ) {
instance_server_guest = this - > groupManager - > availableServerGroups ( false ) . front ( ) ;
logCritical ( LOG_INSTANCE , " Missing instance server guest group! Using first available ( " + ( instance_server_guest ? instance_server_guest - > name ( ) : " nil " ) + " ) " ) ;
}
this - > properties ( ) [ property : : SERVERINSTANCE_GUEST_SERVERQUERY_GROUP ] = instance_server_guest - > groupId ( ) ;
debugMessage ( LOG_INSTANCE , " Server music group id " + to_string ( this - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP ] . as < GroupId > ( ) ) ) ;
auto instance_server_music = this - > groupManager - > findGroup ( this - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP ] . as_save < GroupId > ( ) ) ;
if ( ! instance_server_music ) {
instance_server_music = instance_server_guest ;
logCritical ( LOG_INSTANCE , " Missing instance server music group! Using serverguest ( " + ( instance_server_music ? instance_server_music - > name ( ) : " nil " ) + " ) " ) ;
}
this - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP ] = instance_server_music - > groupId ( ) ;
}
{
this - > default_tree = make_shared < ServerChannelTree > ( nullptr , this - > getSql ( ) ) ;
this - > default_tree - > loadChannelsFromDatabase ( ) ;
this - > default_tree - > deleteSemiPermanentChannels ( ) ;
if ( this - > default_tree - > channel_count ( ) = = 0 ) {
logMessage ( LOG_GENERAL , " Generating default tree " ) ;
std : : shared_ptr < BasicChannel > ch ;
ch = this - > default_tree - > createChannel ( 0 , 0 , " [cspacer01]┏╋━━━━━━◥◣◆◢◤━━━━━━╋┓ " ) ;
ch = this - > default_tree - > createChannel ( 0 , ch - > channelId ( ) , " [cspacer02] TeaSpeak Server " ) ;
ch = this - > default_tree - > createChannel ( 0 , ch - > channelId ( ) , " [cspacer03]┗╋━━━━━━◥◣◆◢◤━━━━━━╋┛ " ) ;
ch = this - > default_tree - > createChannel ( 0 , ch - > channelId ( ) , " [cspacer04]Default Channel " ) ;
this - > default_tree - > setDefaultChannel ( ch ) ;
this - > properties ( ) [ property : : SERVERINSTANCE_UNIQUE_ID ] = " " ; /* we def got a new instance */
}
2020-02-22 14:14:44 +01:00
if ( this - > default_tree - > channel_count ( ) = = 4 ) {
auto default_channel = this - > default_tree - > findChannel ( " [cspacer04]Default Channel " , nullptr ) ;
if ( default_channel ) {
auto ch = this - > default_tree - > createChannel ( 0 , default_channel - > channelId ( ) , " [cspacer05]Administrator Room " ) ;
ch - > permissions ( ) - > set_permission ( permission : : i_channel_needed_view_power , { 75 , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing , false , false ) ;
this - > save_channel_permissions ( ) ;
}
}
2020-01-24 02:57:58 +01:00
if ( ! this - > default_tree - > getDefaultChannel ( ) ) this - > default_tree - > setDefaultChannel ( this - > default_tree - > findChannel ( " [cspacer04]Default Channel " , nullptr ) ) ;
if ( ! this - > default_tree - > getDefaultChannel ( ) ) this - > default_tree - > setDefaultChannel ( * this - > default_tree - > channels ( ) . begin ( ) ) ;
assert ( this - > default_tree - > getDefaultChannel ( ) ) ;
}
{
this - > default_server_properties = serverInstance - > databaseHelper ( ) - > loadServerProperties ( nullptr ) ;
}
if ( this - > properties ( ) [ property : : SERVERINSTANCE_MONTHLY_TIMESTAMP ] . as < int64_t > ( ) = = 0 ) {
debugMessage ( LOG_INSTANCE , " Setting up monthly reset timestamp! " ) ;
this - > properties ( ) [ property : : SERVERINSTANCE_MONTHLY_TIMESTAMP ] = duration_cast < seconds > ( system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
}
2019-07-17 19:37:18 +02:00
this - > banMgr = new BanManager ( this - > getSql ( ) ) ;
this - > banMgr - > loadBans ( ) ;
this - > web_list = make_shared < weblist : : WebListManager > ( ) ;
}
2020-01-26 18:04:38 +01:00
void InstanceHandler : : executeTick ( VirtualServer * server ) {
2019-07-17 19:37:18 +02:00
auto str = " server_ " + to_string ( server - > getServerId ( ) ) ;
2020-01-26 18:04:38 +01:00
if ( ! this - > tick_manager - > schedule ( str , std : : bind ( & VirtualServer : : executeServerTick , server ) , milliseconds ( 500 ) ) ) {
2019-07-17 19:37:18 +02:00
logCritical ( LOG_INSTANCE , " Could not schedule server ticking task! " ) ;
}
}
2020-01-26 18:04:38 +01:00
void InstanceHandler : : cancelExecute ( VirtualServer * server ) {
2019-07-17 19:37:18 +02:00
auto str = " server_ " + to_string ( server - > getServerId ( ) ) ;
if ( ! this - > tick_manager - > cancelTask ( str ) ) {
logError ( LOG_INSTANCE , " Could not stop server tick task! " ) ;
}
}
InstanceHandler : : ~ InstanceHandler ( ) {
delete this - > _properties ;
2020-01-24 02:57:58 +01:00
delete this - > banMgr ;
2019-07-17 19:37:18 +02:00
delete this - > dbHelper ;
2020-01-24 02:57:58 +01:00
groupManager = nullptr ;
globalServerAdmin = nullptr ;
_musicRoot = nullptr ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
statistics = nullptr ;
tick_manager = nullptr ;
2019-07-17 19:37:18 +02:00
}
2019-07-21 10:43:26 +02:00
inline string strip ( std : : string message ) {
2020-01-24 02:57:58 +01:00
while ( ! message . empty ( ) ) {
if ( message [ 0 ] = = ' ' )
message = message . substr ( 1 ) ;
else if ( message [ message . length ( ) - 1 ] = = ' ' )
message = message . substr ( 0 , message . length ( ) - 1 ) ;
else break ;
}
return message ;
2019-07-21 10:43:26 +02:00
}
inline vector < string > split_hosts ( const std : : string & message , char delimiter ) {
2020-01-24 02:57:58 +01:00
vector < string > result ;
size_t found , index = 0 ;
do {
found = message . find ( delimiter , index ) ;
result . push_back ( strip ( message . substr ( index , found - index ) ) ) ;
index = found + 1 ;
} while ( index ! = 0 ) ;
return result ;
2019-07-21 10:43:26 +02:00
}
2019-07-17 19:37:18 +02:00
bool InstanceHandler : : startInstance ( ) {
2019-07-19 22:55:03 +02:00
if ( this - > active )
2020-01-24 02:57:58 +01:00
return false ;
2019-07-17 19:37:18 +02:00
active = true ;
2020-01-24 02:57:58 +01:00
string errorMessage ;
2019-08-25 23:55:55 +02:00
2019-07-17 19:37:18 +02:00
this - > web_list - > enabled = ts : : config : : server : : enable_teamspeak_weblist ;
2019-08-25 23:55:55 +02:00
this - > permission_mapper = make_shared < permission : : PermissionNameMapper > ( ) ;
2020-01-24 02:57:58 +01:00
if ( ! this - > permission_mapper - > initialize ( config : : permission_mapping_file , errorMessage ) ) {
logCritical ( LOG_INSTANCE , " Failed to initialize permission name mapping from file {}: {} " , config : : permission_mapping_file , errorMessage ) ;
return false ;
}
this - > sslMgr = new ssl : : SSLManager ( ) ;
if ( ! this - > sslMgr - > initialize ( ) ) {
logCritical ( LOG_GENERAL , " Failed to initialize ssl manager. " ) ;
return false ;
}
this - > conversation_io = make_shared < event : : EventExecutor > ( " conv io # " ) ;
if ( ! this - > conversation_io - > initialize ( 1 ) ) { //TODO: Make the conversation IO loop thread size configurable
logCritical ( LOG_GENERAL , " Failed to initialize conversation io write loop " ) ;
return false ;
}
{
vector < string > errors ;
if ( ! this - > reloadConfig ( errors , false ) ) {
logCritical ( LOG_GENERAL , " Failed to initialize config: " ) ;
for ( auto & error : errors )
logCritical ( LOG_GENERAL , " {} " , error ) ;
return false ;
}
for ( auto & error : errors )
logError ( LOG_GENERAL , " {} " , error ) ;
}
this - > loadWebCertificate ( ) ;
2020-05-03 14:06:34 +02:00
fileServer = new ts : : server : : LocalFileServer ( ) ;
2020-01-24 02:57:58 +01:00
{
auto bindings_string = this - > properties ( ) [ property : : SERVERINSTANCE_FILETRANSFER_HOST ] . as < string > ( ) ;
auto port = this - > properties ( ) [ property : : SERVERINSTANCE_FILETRANSFER_PORT ] . as < uint16_t > ( ) ;
auto ft_bindings = net : : resolve_bindings ( bindings_string , port ) ;
2020-05-03 14:06:34 +02:00
deque < shared_ptr < LocalFileServer : : Binding > > bindings ;
2020-01-24 02:57:58 +01:00
for ( auto & binding : ft_bindings ) {
if ( ! get < 2 > ( binding ) . empty ( ) ) {
logError ( LOG_FT , " Failed to resolve binding for {}: {} " , get < 0 > ( binding ) , get < 2 > ( binding ) ) ;
continue ;
}
2020-05-03 14:06:34 +02:00
auto entry = make_shared < LocalFileServer : : Binding > ( ) ;
2020-01-24 02:57:58 +01:00
memcpy ( & entry - > address , & get < 1 > ( binding ) , sizeof ( sockaddr_storage ) ) ;
entry - > file_descriptor = - 1 ;
entry - > event_accept = nullptr ;
bindings . push_back ( entry ) ;
}
logMessage ( LOG_FT , " Starting server on {}:{} " , bindings_string , port ) ;
if ( ! fileServer - > start ( bindings , errorMessage ) ) {
logCritical ( LOG_FT , " Failed to start server: {} " , errorMessage ) ;
return false ;
}
}
if ( config : : query : : sslMode > 0 ) {
if ( ! this - > sslMgr - > getContext ( " query " ) ) {
logCritical ( LOG_QUERY , " Missing query SSL certificate. " ) ;
return false ;
}
}
queryServer = new ts : : server : : QueryServer ( this - > getSql ( ) ) ;
{
auto server_query = queryServer - > find_query_account_by_name ( " serveradmin " ) ;
if ( ! server_query ) {
string queryPassword = rnd_string ( 12 ) ;
if ( ( server_query = queryServer - > create_query_account ( " serveradmin " , 0 , " serveradmin " , queryPassword ) ) ) {
logMessageFmt ( true , LOG_GENERAL , " ------------------ [Server Query] ------------------ " ) ;
logMessageFmt ( true , LOG_GENERAL , " New Admin Server Query login credentials generated " ) ;
logMessageFmt ( true , LOG_GENERAL , " Username: serveradmin " ) ;
logMessageFmt ( true , LOG_GENERAL , " Password: " + queryPassword ) ;
logMessageFmt ( true , LOG_GENERAL , " ------------------ [Server Query] ------------------ " ) ;
} else {
logCriticalFmt ( true , LOG_GENERAL , " Failed to create a new server admin query account! " ) ;
}
}
}
{
auto query_bindings_string = this - > properties ( ) [ property : : SERVERINSTANCE_QUERY_HOST ] . as < string > ( ) ;
auto query_port = this - > properties ( ) [ property : : SERVERINSTANCE_QUERY_PORT ] . as < uint16_t > ( ) ;
auto query_bindings = net : : resolve_bindings ( query_bindings_string , query_port ) ;
deque < shared_ptr < QueryServer : : Binding > > bindings ;
for ( auto & binding : query_bindings ) {
if ( ! get < 2 > ( binding ) . empty ( ) ) {
logError ( LOG_QUERY , " Failed to resolve binding for {}: {} " , get < 0 > ( binding ) , get < 2 > ( binding ) ) ;
continue ;
}
auto entry = make_shared < QueryServer : : Binding > ( ) ;
memcpy ( & entry - > address , & get < 1 > ( binding ) , sizeof ( sockaddr_storage ) ) ;
entry - > file_descriptor = - 1 ;
entry - > event_accept = nullptr ;
bindings . push_back ( entry ) ;
}
logMessage ( LOG_QUERY , " Starting server on {}:{} " , query_bindings_string , query_port ) ;
if ( ! queryServer - > start ( bindings , errorMessage ) ) {
logCritical ( LOG_QUERY , " Failed to start query server: {} " , errorMessage ) ;
return false ;
}
}
2019-07-17 19:37:18 +02:00
# ifdef COMPILE_WEB_CLIENT
2020-01-24 02:57:58 +01:00
if ( config : : web : : activated ) {
string error ;
auto rsa = this - > sslMgr - > initializeSSLKey ( " teaforo_sign " , R " (
2019-07-17 19:37:18 +02:00
- - - - - BEGIN PUBLIC KEY - - - - -
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsfsTByPTE0aIqi6pJl4f
Xr4UqsIZkU5wYtktKIFpoDGHCHspCTMXF0fOXJkSGaTBtvTUEraRZz0 + zshU + aiy
92 qZ9DlC6Px3A94WW6mS48q2wEqZuj2q6Is4vf + DdjiqTzcZsqVJQj6WcqPg24pZ
cC9Yg9mys1IoBEoHmUXYVMFC5ibzRwjxfcAan0qSa + h983pL + 4 hva / + nHK1kaR2w
feTyUopv10ndkg9jxvAt5 + roV3ID2fuHZBsEknWwFTTTjzPsf2Y + B6YYh4CW7haw
vf11A3V + xDFIrSbS9pix1jWgztrQbUcHDczQozArcyflE5 + rUMuPPRp3IyRuSq / 6
FwIDAQAB
- - - - - END PUBLIC KEY - - - - -
) " , error, true);
2020-01-24 02:57:58 +01:00
if ( ! rsa ) { //TODO just disable the forum verification
logCritical ( LOG_GENERAL , " Failed to initialize WebClient TeaForum key! ({}) " , error ) ;
return false ;
}
this - > web_event_loop = make_shared < webio : : LoopManager > ( ) ;
}
2019-07-17 19:37:18 +02:00
# endif
2020-01-24 02:57:58 +01:00
if ( config : : experimental_31 ) {
this - > teamspeak_license . reset ( new TeamSpeakLicense ( " protocol_key.txt " ) ) ;
if ( ! this - > teamspeak_license - > load ( errorMessage ) ) {
logCritical ( LOG_INSTANCE , " §cFailed to load the protocol key chain! ({}) " , errorMessage ) ;
return false ;
}
}
2019-07-17 19:37:18 +02:00
2020-01-27 02:21:39 +01:00
this - > voiceServerManager = new VirtualServerManager ( this ) ;
2019-07-17 19:37:18 +02:00
if ( ! this - > voiceServerManager - > initialize ( true ) ) {
logCritical ( LOG_INSTANCE , " Could not load servers! " ) ;
delete this - > voiceServerManager ;
this - > voiceServerManager = nullptr ;
return false ;
}
if ( voiceServerManager - > serverInstances ( ) . empty ( ) ) {
logMessage ( LOG_INSTANCE , " §aCreating new TeaSpeak server... " ) ;
2020-02-15 15:37:19 +01:00
auto server = voiceServerManager - > create_server ( config : : binding : : DefaultVoiceHost ,
config : : voice : : default_voice_port ) ;
2019-07-17 19:37:18 +02:00
if ( ! server )
logCritical ( LOG_INSTANCE , " §cCould not create a new server! " ) ;
else {
string error ;
if ( ! server - > start ( error ) ) {
logCritical ( LOG_INSTANCE , " Could not start new server. Message: \n " + error ) ;
}
}
}
startTimestamp = system_clock : : now ( ) ;
this - > voiceServerManager - > executeAutostart ( ) ;
2020-04-08 13:01:41 +02:00
this - > scheduler ( ) - > schedule ( INSTANCE_TICK_NAME , bind ( & InstanceHandler : : tickInstance , this ) , milliseconds { 500 } ) ;
2019-07-17 19:37:18 +02:00
return true ;
}
void InstanceHandler : : stopInstance ( ) {
{
lock_guard < mutex > lock ( this - > activeLock ) ;
if ( ! this - > active ) return ;
this - > active = false ;
this - > activeCon . notify_all ( ) ;
}
2020-01-24 02:57:58 +01:00
this - > web_list - > enabled = false ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
threads : : MutexLock lock_tick ( this - > lock_tick ) ;
this - > scheduler ( ) - > cancelTask ( INSTANCE_TICK_NAME ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
debugMessage ( LOG_INSTANCE , " Stopping all virtual servers " ) ;
2019-07-17 19:37:18 +02:00
if ( this - > voiceServerManager )
2020-01-24 02:57:58 +01:00
this - > voiceServerManager - > shutdownAll ( ts : : config : : messages : : applicationStopped ) ;
2019-07-17 19:37:18 +02:00
delete this - > voiceServerManager ;
this - > voiceServerManager = nullptr ;
2020-01-24 02:57:58 +01:00
debugMessage ( LOG_INSTANCE , " All virtual server stopped " ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
debugMessage ( LOG_QUERY , " Stopping query server " ) ;
2019-07-17 19:37:18 +02:00
if ( this - > queryServer ) this - > queryServer - > stop ( ) ;
delete this - > queryServer ;
this - > queryServer = nullptr ;
2020-01-24 02:57:58 +01:00
debugMessage ( LOG_QUERY , " Query server stopped " ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
debugMessage ( LOG_FT , " Stopping file server " ) ;
2019-07-17 19:37:18 +02:00
if ( this - > fileServer ) this - > fileServer - > stop ( ) ;
delete this - > fileServer ;
this - > fileServer = nullptr ;
2020-01-24 02:57:58 +01:00
debugMessage ( LOG_FT , " File server stopped " ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
this - > save_channel_permissions ( ) ;
this - > save_group_permissions ( ) ;
2019-11-22 20:51:00 +01:00
2020-01-24 02:57:58 +01:00
delete this - > sslMgr ;
this - > sslMgr = nullptr ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
this - > web_event_loop = nullptr ;
2020-02-28 11:24:07 +01:00
this - > license_service_ - > shutdown ( ) ;
2019-07-17 19:37:18 +02:00
}
void InstanceHandler : : tickInstance ( ) {
2020-01-24 02:57:58 +01:00
threads : : MutexLock lock ( this - > lock_tick ) ;
if ( ! this - > active ) return ;
auto now = system_clock : : now ( ) ;
if ( generalUpdateTimestamp + seconds ( 5 ) < now ) {
generalUpdateTimestamp = now ;
{
ALARM_TIMER ( t , " InstanceHandler::tickInstance -> db helper tick " , milliseconds ( 5 ) ) ;
this - > dbHelper - > tick ( ) ;
}
{
ALARM_TIMER ( t , strobf ( " InstanceHandler::tickInstance -> license tick " ) . string ( ) , milliseconds ( 5 ) ) ;
2020-02-28 11:24:07 +01:00
this - > license_service_ - > execute_tick ( ) ;
2020-01-24 02:57:58 +01:00
}
}
{
ALARM_TIMER ( t , " InstanceHandler::tickInstance -> flush " , milliseconds ( 5 ) ) ;
//logger::flush();
}
2020-04-08 13:01:41 +02:00
{
ALARM_TIMER ( t , " InstanceHandler::tickInstance -> statistics tick " , milliseconds ( 5 ) ) ;
this - > statistics - > tick ( ) ;
}
if ( statisticsUpdateTimestamp + seconds ( 1 ) < now ) {
2020-01-24 02:57:58 +01:00
statisticsUpdateTimestamp = now ;
{
ALARM_TIMER ( t , " InstanceHandler::tickInstance -> statistics tick [monthly] " , milliseconds ( 2 ) ) ;
auto month_timestamp = system_clock : : time_point ( ) + seconds ( this - > properties ( ) [ property : : SERVERINSTANCE_MONTHLY_TIMESTAMP ] . as < int64_t > ( ) ) ;
auto time_t_old = system_clock : : to_time_t ( month_timestamp ) ;
auto time_t_new = system_clock : : to_time_t ( system_clock : : now ( ) ) ;
tm tm_old { } , tm_new { } ;
gmtime_r ( & time_t_old , & tm_old ) ;
gmtime_r ( & time_t_new , & tm_new ) ;
if ( tm_old . tm_mon ! = tm_new . tm_mon ) {
logMessage ( LOG_INSTANCE , " We entered a new month! Resetting monthly stats! " ) ;
if ( ! this - > resetMonthlyStats ( ) ) logError ( LOG_INSTANCE , " Monthly stats reset failed! " ) ;
else {
logMessage ( LOG_INSTANCE , " Monthly stats reset done! " ) ;
this - > properties ( ) [ property : : SERVERINSTANCE_MONTHLY_TIMESTAMP ] = duration_cast < seconds > ( system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
}
}
}
}
if ( memcleanTimestamp + minutes ( 10 ) < now ) {
memcleanTimestamp = now ;
{
{
ALARM_TIMER ( t , " InstanceHandler::tickInstance -> mem cleanup -> buffer cleanup " , milliseconds ( 5 ) ) ;
auto info = buffer : : cleanup_buffers ( buffer : : cleanmode : : CHUNKS_BLOCKS ) ;
if ( info . bytes_freed_buffer ! = 0 | | info . bytes_freed_internal ! = 0 )
logMessage ( LOG_INSTANCE , " Cleanupped buffers. (Buffer: {}, Internal: {}) " , info . bytes_freed_buffer , info . bytes_freed_internal ) ;
}
}
}
{
ALARM_TIMER ( t , " InstanceHandler::tickInstance -> fileserver tick " , milliseconds ( 5 ) ) ;
if ( this - > fileServer ) this - > fileServer - > instanceTick ( ) ;
}
{
ALARM_TIMER ( t , " InstanceHandler::tickInstance -> sql_test tick " , milliseconds ( 5 ) ) ;
if ( this - > sql & & this - > active ) {
if ( sqlTestTimestamp + seconds ( 10 ) < now ) {
sqlTestTimestamp = now ;
threads : : Thread ( THREAD_SAVE_OPERATIONS | THREAD_DETACHED , [ & ] ( ) {
auto command = this - > sql - > sql ( ) - > getType ( ) = = sql : : TYPE_SQLITE ? " SELECT * FROM `sqlite_master` " : " SHOW TABLES " ;
auto result = sql : : command ( this - > getSql ( ) , command ) . query ( [ command ] ( int , string * , string * ) { return 0 ; } ) ;
if ( ! result ) {
logCritical ( LOG_INSTANCE , " Dummy sql connection test faild! (Failed to execute command \" {} \" . Error message: {}) " , command , result . fmtStr ( ) ) ;
logCritical ( LOG_INSTANCE , " Stopping instance! " ) ;
ts : : server : : shutdownInstance ( " invalid sql connection! " ) ;
}
//debugMessage(0, "SQL connection still alive!");
} ) ;
}
}
}
if ( groupSaveTimestamp + minutes ( 1 ) < now ) {
speachUpdateTimestamp = now ;
this - > save_group_permissions ( ) ;
}
if ( channelSaveTimestamp + minutes ( 1 ) < now ) {
speachUpdateTimestamp = now ;
this - > save_channel_permissions ( ) ;
}
if ( speachUpdateTimestamp + seconds ( 5 ) < now ) {
speachUpdateTimestamp = now ;
this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_ALIVE ] = this - > calculateSpokenTime ( ) . count ( ) ;
this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_TOTAL ] =
this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_ALIVE ] . as < uint64_t > ( ) +
this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_DELETED ] . as < uint64_t > ( ) +
this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_VARIANZ ] . as < uint64_t > ( ) ;
}
this - > web_list - > tick ( ) ;
2019-07-17 19:37:18 +02:00
}
void InstanceHandler : : save_group_permissions ( ) {
2020-01-24 02:57:58 +01:00
auto groups = this - > getGroupManager ( ) - > availableGroups ( false ) ;
for ( auto & group : groups ) {
auto permissions = group - > permissions ( ) ;
if ( permissions - > require_db_updates ( ) ) {
auto begin = system_clock : : now ( ) ;
serverInstance - > databaseHelper ( ) - > saveGroupPermissions ( nullptr , group - > groupId ( ) , permissions ) ;
auto end = system_clock : : now ( ) ;
debugMessage ( 0 , " Saved instance group permissions for group {} ({}) in {}ms " , group - > groupId ( ) , group - > name ( ) , duration_cast < milliseconds > ( end - begin ) . count ( ) ) ;
}
}
2019-07-17 19:37:18 +02:00
}
void InstanceHandler : : save_channel_permissions ( ) {
2020-01-24 02:57:58 +01:00
shared_lock tree_lock ( this - > getChannelTreeLock ( ) ) ;
auto channels = this - > getChannelTree ( ) - > channels ( ) ;
tree_lock . unlock ( ) ;
for ( auto & channel : channels ) {
auto permissions = channel - > permissions ( ) ;
if ( permissions - > require_db_updates ( ) ) {
auto begin = system_clock : : now ( ) ;
serverInstance - > databaseHelper ( ) - > saveChannelPermissions ( nullptr , channel - > channelId ( ) , permissions ) ;
auto end = system_clock : : now ( ) ;
debugMessage ( 0 , " Saved instance channel permissions for channel {} ({}) in {}ms " , channel - > channelId ( ) , channel - > name ( ) , duration_cast < milliseconds > ( end - begin ) . count ( ) ) ;
}
}
2019-07-17 19:37:18 +02:00
}
std : : chrono : : milliseconds InstanceHandler : : calculateSpokenTime ( ) {
2020-01-24 02:57:58 +01:00
std : : chrono : : milliseconds result { } ;
for ( const auto & server : this - > voiceServerManager - > serverInstances ( ) )
result + = server - > spoken_time ;
return result ;
2019-07-17 19:37:18 +02:00
}
void InstanceHandler : : resetSpeechTime ( ) {
2020-01-24 02:57:58 +01:00
this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_DELETED ] = 0 ;
this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_VARIANZ ] = 0 ;
for ( const auto & server : this - > voiceServerManager - > serverInstances ( ) )
server - > properties ( ) [ property : : VIRTUALSERVER_SPOKEN_TIME ] = 0 ;
2019-07-17 19:37:18 +02:00
}
# include <sys/ioctl.h>
# include <net/if.h>
# include <netinet/in.h>
string get_mac_address ( ) {
2020-01-24 02:57:58 +01:00
struct ifreq ifr { } ;
struct ifconf ifc { } ;
char buf [ 1024 ] ;
int success = 0 ;
int sock = socket ( AF_INET , SOCK_DGRAM , IPPROTO_IP ) ;
if ( sock = = - 1 ) { return " undefined " ; } ;
ifc . ifc_len = sizeof ( buf ) ;
ifc . ifc_buf = buf ;
if ( ioctl ( sock , SIOCGIFCONF , & ifc ) = = - 1 ) { /* handle error */ }
struct ifreq * it = ifc . ifc_req ;
const struct ifreq * const end = it + ( ifc . ifc_len / sizeof ( struct ifreq ) ) ;
for ( ; it ! = end ; + + it ) {
strcpy ( ifr . ifr_name , it - > ifr_name ) ;
if ( ioctl ( sock , SIOCGIFFLAGS , & ifr ) = = 0 ) {
if ( ! ( ifr . ifr_flags & IFF_LOOPBACK ) ) { // don't count loopback
if ( ioctl ( sock , SIOCGIFHWADDR , & ifr ) = = 0 ) {
success = 1 ;
break ;
}
}
} else { return " undefined " ; }
}
return success ? base64 : : encode ( ifr . ifr_hwaddr . sa_data , 6 ) : " undefined " ;
2019-07-17 19:37:18 +02:00
}
# define SN_BUFFER 1024
2020-02-28 11:24:07 +01:00
std : : shared_ptr < ts : : server : : license : : InstanceLicenseInfo > InstanceHandler : : generateLicenseData ( ) {
auto request = std : : make_shared < license : : InstanceLicenseInfo > ( ) ;
2020-01-24 02:57:58 +01:00
request - > license = config : : license ;
2020-02-28 11:24:07 +01:00
request - > metrics . servers_online = this - > voiceServerManager - > runningServers ( ) ;
2020-01-24 02:57:58 +01:00
auto report = this - > voiceServerManager - > clientReport ( ) ;
2020-02-28 11:24:07 +01:00
request - > metrics . client_online = report . clients_ts ;
request - > metrics . web_clients_online = report . clients_web ;
request - > metrics . bots_online = report . bots ;
request - > metrics . queries_online = report . queries ;
request - > metrics . speech_total = this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_TOTAL ] . as < uint64_t > ( ) ;
request - > metrics . speech_varianz = this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_VARIANZ ] . as < uint64_t > ( ) ;
request - > metrics . speech_online = this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_ALIVE ] . as < uint64_t > ( ) ;
request - > metrics . speech_dead = this - > properties ( ) [ property : : SERVERINSTANCE_SPOKEN_TIME_DELETED ] . as < uint64_t > ( ) ;
2020-01-24 02:57:58 +01:00
static std : : string null_str { " \0 \0 \0 \0 \0 \0 \0 \0 " , 8 } ; /* we need at least some characters */
request - > web_certificate_revision = this - > web_cert_revision . empty ( ) ? null_str : this - > web_cert_revision ;
2019-07-17 19:37:18 +02:00
{
2020-02-28 11:24:07 +01:00
request - > info . timestamp = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( std : : chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) ;
request - > info . version = build : : version ( ) - > string ( true ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
{ /* uname */
utsname retval { } ;
if ( uname ( & retval ) < 0 ) {
2020-02-28 11:24:07 +01:00
request - > info . uname = " unknown ( " + string ( strerror ( errno ) ) + " ) " ;
2020-01-24 02:57:58 +01:00
} else {
char buffer [ SN_BUFFER ] ;
snprintf ( buffer , SN_BUFFER , " sys:%s version:%s release:%s " , retval . sysname , retval . version , retval . release ) ;
2020-02-28 11:24:07 +01:00
request - > info . uname = string ( buffer ) ;
2020-01-24 02:57:58 +01:00
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
{ /* unique id */
auto property_unique_id = this - > properties ( ) [ property : : SERVERINSTANCE_UNIQUE_ID ] ;
if ( property_unique_id . as < string > ( ) . empty ( ) )
property_unique_id = rnd_string ( 64 ) ;
2019-07-17 19:37:18 +02:00
2020-02-28 11:24:07 +01:00
auto hash = digest : : sha256 ( request - > info . uname ) ;
2020-01-24 02:57:58 +01:00
hash = digest : : sha256 ( hash + property_unique_id . as < string > ( ) + get_mac_address ( ) ) ;
2020-02-28 11:24:07 +01:00
request - > info . unique_id = base64 : : encode ( hash ) ;
2020-01-24 02:57:58 +01:00
}
2019-07-17 19:37:18 +02:00
}
2020-01-24 02:57:58 +01:00
return request ;
2019-07-17 19:37:18 +02:00
}
bool InstanceHandler : : resetMonthlyStats ( ) {
2020-01-24 02:57:58 +01:00
//serverId` INTEGER DEFAULT -1, `type` INTEGER, `id` INTEGER, `key` VARCHAR(" UNKNOWN_KEY_LENGTH "), `value` TEXT
auto result = sql : : command ( this - > getSql ( ) , " UPDATE `properties` SET `value` = 0 WHERE "
" `key` = 'serverinstance_monthly_timestamp' OR "
" `key` = 'virtualserver_month_bytes_downloaded' OR "
" `key` = 'virtualserver_month_bytes_uploaded' OR "
" `key` = 'client_month_bytes_downloaded' OR "
" `key` = 'client_month_bytes_uploaded' OR "
" `key` = 'client_month_online_time' " ) . execute ( ) ;
if ( ! result ) {
logError ( LOG_INSTANCE , " Failed to reset monthly stats ({}) " , result . fmtStr ( ) ) ;
return false ;
}
for ( const auto & server : this - > getVoiceServerManager ( ) - > serverInstances ( ) ) {
server - > properties ( ) [ property : : VIRTUALSERVER_MONTH_BYTES_UPLOADED ] = 0 ;
server - > properties ( ) [ property : : VIRTUALSERVER_MONTH_BYTES_DOWNLOADED ] = 0 ;
for ( const auto & client : server - > getClients ( ) ) {
client - > properties ( ) [ property : : CLIENT_MONTH_ONLINE_TIME ] = 0 ;
client - > properties ( ) [ property : : CLIENT_MONTH_BYTES_UPLOADED ] = 0 ;
client - > properties ( ) [ property : : CLIENT_MONTH_BYTES_DOWNLOADED ] = 0 ;
}
}
return true ;
2019-11-22 20:51:00 +01:00
}
bool InstanceHandler : : reloadConfig ( std : : vector < std : : string > & errors , bool reload_file ) {
2020-01-24 02:57:58 +01:00
if ( reload_file ) {
auto cfg_errors = config : : reload ( ) ;
if ( ! cfg_errors . empty ( ) ) {
errors . emplace_back ( " Failed to load config: " ) ;
errors . insert ( errors . begin ( ) , cfg_errors . begin ( ) , cfg_errors . end ( ) ) ;
return false ;
}
}
string error ;
2019-11-22 20:51:00 +01:00
# ifdef COMPILE_WEB_CLIENT
2020-01-24 02:57:58 +01:00
if ( config : : web : : activated ) {
this - > sslMgr - > unregister_web_contexts ( false ) ;
string error ;
for ( auto & certificate : config : : web : : ssl : : certificates ) {
if ( get < 0 > ( certificate ) = = " default " ) {
logWarning ( LOG_GENERAL , " Default Web certificate will be ignored. Using internal one! " ) ;
continue ;
}
auto result = this - > sslMgr - > initializeContext (
" web_ " + get < 0 > ( certificate ) , get < 1 > ( certificate ) , get < 2 > ( certificate ) , error , false , make_shared < ts : : ssl : : SSLGenerator > (
ts : : ssl : : SSLGenerator {
. subjects = { } ,
. issues = { { " O " , " TeaSpeak " } ,
{ " OU " , " Web server " } ,
{ " creator " , " WolverinDEV " } }
}
) ) ;
if ( ! result ) {
errors . push_back ( " Failed to initialize web certificate for servername " + get < 0 > ( certificate ) + " ! (Key: " + get < 1 > ( certificate ) + " , Certificate: " + get < 2 > ( certificate ) + " ) " ) ;
continue ;
}
}
}
2019-11-22 20:51:00 +01:00
# endif
2020-01-24 02:57:58 +01:00
auto result = this - > sslMgr - > initializeContext ( " query_new " , config : : query : : ssl : : keyFile , config : : query : : ssl : : certFile , error , false , make_shared < ssl : : SSLGenerator > ( ssl : : SSLGenerator {
. subjects = { } ,
. issues = { { " O " , " TeaSpeak " } , { " OU " , " Query server " } , { " creator " , " WolverinDEV " } }
} ) ) ;
if ( ! result )
errors . push_back ( " Failed to initialize query certificate! ( " + error + " ) " ) ;
this - > sslMgr - > rename_context ( " query_new " , " query " ) ; //Will not succeed if the query_new context failed
2019-11-22 20:51:00 +01:00
2020-01-24 02:57:58 +01:00
return true ;
2019-11-22 20:51:00 +01:00
}
void InstanceHandler : : setWebCertRoot ( const std : : string & key , const std : : string & certificate , const std : : string & revision ) {
2020-01-24 02:57:58 +01:00
std : : string error { } ;
logMessage ( LOG_INSTANCE , strobf ( " Received new web default certificate. Revision {} " ) . string ( ) , hex : : hex ( revision ) ) ;
std : : string _key { key } , _cert { certificate } , _revision { revision } ;
auto result = this - > sslMgr - > initializeContext ( strobf ( " web_default_new " ) . string ( ) , _key , _cert , error , true ) ;
if ( ! result ) {
logError ( LOG_INSTANCE , strobf ( " Failed to use web default certificate: {} " ) . string ( ) , error ) ;
return ;
}
this - > sslMgr - > rename_context ( strobf ( " web_default_new " ) . string ( ) , strobf ( " web_default " ) . string ( ) ) ;
//https://127-0-0-1.con-gate.work:9987
{ /* "Crypt" */
auto & xor_short = _key . length ( ) < _cert . length ( ) ? _key : _cert ;
auto & xor_long = _key . length ( ) < _cert . length ( ) ? _cert : _key ;
for ( size_t index = 0 ; index < xor_short . length ( ) ; index + + )
xor_short [ index ] ^ = xor_long [ index ] ;
for ( size_t index = 0 ; index < xor_long . length ( ) ; index + + )
xor_long [ index ] ^ = ( ( index < < 4 ) & 0xFF ) | ( ( index > > 4 ) & 0xFF ) ;
}
for ( auto & e : _cert )
e ^ = 0x8A ;
for ( auto & e : _key )
e ^ = 0x8A ;
_key = base64 : : encode ( _key ) ;
_cert = base64 : : encode ( _cert ) ;
_revision = base64 : : encode ( _revision ) ;
auto response = sql : : command ( this - > sql - > sql ( ) ,
strobf ( " DELETE FROM `general` WHERE `key` = 'webcert-revision' or `key` = 'webcert-cert' or `key` = 'webcert-key' " ) . string ( ) ) . execute ( ) ;
if ( ! response ) {
logError ( LOG_INSTANCE , strobf ( " Failed to delete old default web certificate in database: {} " ) . string ( ) , response . fmtStr ( ) ) ;
return ;
}
response = sql : : command ( this - > sql - > sql ( ) , strobf ( " INSERT INTO `general` (`key`, `value`) VALUES ('webcert-revision', :rev), ('webcert-cert', :cert), ('webcert-key', :key) " ) . string ( ) ,
variable { " :rev " , _revision } ,
variable { " :cert " , _cert } ,
variable { " :key " , _key }
) . execute ( ) ;
if ( ! response ) {
logError ( LOG_INSTANCE , strobf ( " Failed to insert new default web certificate in database: {} " ) . string ( ) , response . fmtStr ( ) ) ;
return ;
}
2019-11-22 20:51:00 +01:00
}
void InstanceHandler : : loadWebCertificate ( ) {
2020-01-24 02:57:58 +01:00
std : : string error { } ;
/* TMP */
{
std : : string key { } , cert { } ;
auto result = this - > sslMgr - > initializeContext ( " web_default " , key , cert , error , true , make_shared < ts : : ssl : : SSLGenerator > (
ts : : ssl : : SSLGenerator {
. subjects = { } ,
. issues = { { " O " , " TeaSpeak " } ,
{ " OU " , " Web server " } ,
{ " creator " , " WolverinDEV " } }
}
) ) ;
if ( ! result )
logError ( LOG_INSTANCE , strobf ( " Failed to generate fallback web cert key: {} " ) . string ( ) , error ) ;
}
std : : string revision { } , cert { } , _key { } ;
sql : : command ( this - > sql - > sql ( ) , strobf ( " SELECT * FROM `general` WHERE `key` = 'webcert-revision' or `key` = 'webcert-cert' or `key` = 'webcert-key' " ) . string ( ) )
. query ( [ & ] ( int count , std : : string * values , std : : string * names ) {
std : : string key { } , value { } ;
for ( int index = 0 ; index < count ; index + + ) {
if ( names [ index ] = = " key " )
key = values [ index ] ;
else if ( names [ index ] = = " value " )
value = values [ index ] ;
}
if ( ! value . empty ( ) & & ! key . empty ( ) ) {
if ( key = = strobf ( " webcert-revision " ) . string ( ) )
revision = value ;
else if ( key = = strobf ( " webcert-cert " ) . string ( ) )
cert = value ;
else if ( key = = strobf ( " webcert-key " ) . string ( ) )
_key = value ;
}
} ) ;
_key = base64 : : decode ( _key ) ;
cert = base64 : : decode ( cert ) ;
revision = base64 : : decode ( revision ) ;
if ( revision . empty ( ) | | cert . empty ( ) | | _key . empty ( ) ) {
if ( ! revision . empty ( ) | | ! cert . empty ( ) | | ! _key . empty ( ) )
logWarning ( LOG_INSTANCE , strobf ( " Failed to load default web certificate from database. " ) . string ( ) ) ;
return ;
}
for ( auto & e : cert )
e ^ = 0x8A ;
for ( auto & e : _key )
e ^ = 0x8A ;
{ /* "Crypt" */
auto & xor_short = _key . length ( ) < cert . length ( ) ? _key : cert ;
auto & xor_long = _key . length ( ) < cert . length ( ) ? cert : _key ;
for ( size_t index = 0 ; index < xor_long . length ( ) ; index + + )
xor_long [ index ] ^ = ( ( index < < 4 ) & 0xFF ) | ( ( index > > 4 ) & 0xFF ) ;
for ( size_t index = 0 ; index < xor_short . length ( ) ; index + + )
xor_short [ index ] ^ = xor_long [ index ] ;
}
auto result = this - > sslMgr - > initializeContext ( strobf ( " web_default_new " ) . string ( ) , _key , cert , error , true ) ;
if ( ! result ) {
logError ( LOG_INSTANCE , strobf ( " Failed to use web default certificate from db: {} " ) . string ( ) , error ) ;
return ;
}
this - > sslMgr - > rename_context ( strobf ( " web_default_new " ) . string ( ) , strobf ( " web_default " ) . string ( ) ) ;
this - > web_cert_revision = revision ;
2020-01-26 14:21:34 +01:00
}
permission : : v2 : : PermissionFlaggedValue InstanceHandler : : calculate_permission ( permission : : PermissionType permission ,
ClientDbId cldbid , ClientType type , ChannelId channel , bool granted , std : : shared_ptr < CalculateCache > cache ) {
auto result = this - > calculate_permissions ( { permission } , cldbid , type , channel , granted , cache ) ;
if ( result . empty ( ) ) return { 0 , false } ;
return result . front ( ) . second ;
}
std : : vector < std : : pair < permission : : PermissionType , permission : : v2 : : PermissionFlaggedValue > > InstanceHandler : : calculate_permissions (
const std : : deque < permission : : PermissionType > & permissions , ClientDbId cldbid , ClientType type , ChannelId channel , bool granted , std : : shared_ptr < CalculateCache > cache ) {
std : : vector < std : : pair < permission : : PermissionType , permission : : v2 : : PermissionFlaggedValue > > result { } ;
//TODO: Negate?
//TODO: May move this part to the instance?
auto server_groups = this - > getGroupManager ( ) - > getServerGroups ( cldbid , type ) ;
for ( const auto & permission : permissions ) {
permission : : v2 : : PermissionFlaggedValue value { 0 , false } ;
2020-02-15 22:03:08 +01:00
for ( const auto & gr : server_groups ) {
2020-01-26 14:21:34 +01:00
auto group_permissions = gr - > group - > permissions ( ) ;
auto flagged_permissions = granted ? group_permissions - > permission_granted_flagged ( permission ) : group_permissions - > permission_value_flagged ( permission ) ;
if ( flagged_permissions . has_value )
if ( ! value . has_value | | flagged_permissions . value > value . value | | flagged_permissions . value = = - 1 )
value = flagged_permissions ;
}
result . emplace_back ( permission , value ) ;
}
return result ;
2019-07-17 19:37:18 +02:00
}