#include #include #include #include #include #include #include "../../InstanceHandler.h" #include "../../geo/GeoLocation.h" #include "VoiceClient.h" using namespace std; using namespace std::chrono; using namespace ts::server; using namespace ts::protocol; using namespace ts; CommandResult VoiceClient::handleCommand(ts::Command &command) { threads::MutexLock l2(this->command_lock); if(this->state == ConnectionState::DISCONNECTED) return CommandResult::NotImplemented; if(!this->voice_server) return CommandResult::NotImplemented; if(this->state == ConnectionState::INIT_HIGH && this->handshake.state == HandshakeState::SUCCEEDED) { if(command.command() == "clientinit") return this->handleCommandClientInit(command); } else if(command.command() == "clientdisconnect") return this->handleCommandClientDisconnect(command); return SpeakingClient::handleCommand(command); } inline bool calculate_security_level(int& result, ecc_key* pubKey, size_t offset) { size_t pubLength = 256; char pubBuffer[256]; if((result = ecc_export(reinterpret_cast(pubBuffer), &pubLength, PK_PUBLIC, pubKey)) != CRYPT_OK) return false; std::string hashStr = base64_encode(pubBuffer, pubLength) + to_string(offset); char shaBuffer[SHA_DIGEST_LENGTH]; SHA1((const unsigned char *) hashStr.data(), hashStr.length(), (unsigned char *) shaBuffer); //Leading zero bits int zeroBits = 0; int i; for(i = 0; i < SHA_DIGEST_LENGTH; i++) if(shaBuffer[i] == 0) zeroBits += 8; else break; if(i < SHA_DIGEST_LENGTH) { for(int bit = 0; bit < 8; bit++) { if((shaBuffer[i] & (1 << bit)) == 0) zeroBits++; else break; } } result = zeroBits; return true; } CommandResult VoiceClient::handleCommandClientInit(Command &cmd) { this->crypto.client_init = true; this->connection->acknowledge_handler.reset(); if(this->getType() == ClientType::CLIENT_TEAMSPEAK) { int securityLevel; if(!calculate_security_level(securityLevel, this->crypto.remote_key.get(), cmd["client_key_offset"])) { logError(this->getServerId(), "[{}] Failed to calculate security level. Error code: {}", CLIENT_STR_LOG_PREFIX, securityLevel); return {ErrorType::VSError}; } if(securityLevel < 8) return {findError("channel_invalid_security_hash"), "cant calculate security level"}; auto requiredLevel = this->getServer()->properties()[property::VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL].as(); if(securityLevel < requiredLevel) return {findError("client_could_not_validate_identity"), to_string(requiredLevel)}; } this->lastPingResponse = std::chrono::system_clock::now(); return SpeakingClient::handleCommandClientInit(cmd); } CommandResult VoiceClient::handleCommandClientDisconnect(Command& cmd) { auto reason = cmd["reasonmsg"].size() > 0 ? cmd["reasonmsg"].as() : ""; this->disconnect(VREASON_SERVER_LEFT, reason, nullptr, true); logMessage(this->getServerId(), "{} Got remote disconnect with the reason '{}'", CLIENT_STR_LOG_PREFIX, reason); return CommandResult::Success; }