#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; command_result VoiceClient::handleCommand(ts::Command &command) { threads::MutexLock l2(this->command_lock); if(this->state == ConnectionState::DISCONNECTED) return command_result{error::client_not_logged_in}; if(!this->voice_server) return command_result{error::server_unbound}; 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(uint8_t bit = 0; bit < 8; bit++) { if((shaBuffer[i] & (1U << bit)) == 0) zeroBits++; else break; } } result = zeroBits; return true; } command_result 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 command_result{error::vs_critical}; } if(securityLevel < 8) return command_result{error::client_could_not_validate_identity}; auto requiredLevel = this->getServer()->properties()[property::VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL].as(); if(securityLevel < requiredLevel) return command_result{error::client_could_not_validate_identity, to_string(requiredLevel)}; } this->lastPingResponse = std::chrono::system_clock::now(); return SpeakingClient::handleCommandClientInit(cmd); } command_result VoiceClient::handleCommandClientDisconnect(Command& cmd) { auto reason = cmd["reasonmsg"].size() > 0 ? cmd["reasonmsg"].as() : ""; this->notifyClientLeftView(this->ref(), nullptr, VREASON_SERVER_LEFT, reason, nullptr, false); //Before we're moving us out of the channel tree! if(this->state == CONNECTED) { unique_lock channel_lock(this->server->channel_tree_lock); this->server->client_move(this->ref(), nullptr, nullptr, reason, VREASON_SERVER_LEFT, true, channel_lock); } logMessage(this->getServerId(), "{} Got remote disconnect with the reason '{}'", CLIENT_STR_LOG_PREFIX, reason); this->postCommandHandler.push_back([&]{ this->close_connection(std::chrono::system_clock::now() + std::chrono::seconds{1}); /* send acknowledge and close connection */ }); return command_result{error::ok}; }