#include #include #include #include #include #include #include "../../InstanceHandler.h" #include "VoiceClient.h" using namespace std; using namespace std::chrono; using namespace ts::server; using namespace ts::protocol; using namespace ts; void VoiceClient::handlePacketCommand(const pipes::buffer_view& command_string) { std::unique_ptr command; command_result result{}; try { command = make_unique(Command::parse(command_string, true, !ts::config::server::strict_ut8_mode)); } catch(std::invalid_argument& ex) { result.reset(command_result{error::parameter_convert, std::string{ex.what()}}); goto handle_error; } catch(std::exception& ex) { result.reset(command_result{error::parameter_convert, std::string{ex.what()}}); goto handle_error; } this->handleCommandFull(*command, true); return; handle_error: this->notifyError(result); result.release_data(); } 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) { if(this->getType() == ClientType::CLIENT_TEAMSPEAK) { auto client_identity = this->connection->crypt_setup_handler().identity_key(); int security_level; if(!calculate_security_level(security_level, &*client_identity, cmd["client_key_offset"])) { logError(this->getServerId(), "[{}] Failed to calculate security level. Error code: {}", CLIENT_STR_LOG_PREFIX, security_level); return command_result{error::vs_critical}; } if(security_level < 8) { return command_result{error::client_could_not_validate_identity}; } auto requiredLevel = this->getServer()->properties()[property::VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL].as(); if(security_level < requiredLevel) { return command_result{error::client_could_not_validate_identity, to_string(requiredLevel)}; } } 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}; }