diff options
| author | Shauren <shauren.trinity@gmail.com> | 2014-07-19 03:38:57 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2014-07-19 03:51:11 +0200 |
| commit | 909acdbac3223d8c788b1b5dc42b6dfab8b604ab (patch) | |
| tree | 2a0ade312aad77ca032015c6957a4a9005aa0b94 /src/server/worldserver/RemoteAccess | |
| parent | 5daf3d360686ea8ff2d97a48fca24f0bf42ef098 (diff) | |
| parent | 1866d8cc06e2b8c2722ccf69ee3f52ceda93bc27 (diff) | |
Merge remote-tracking branch 'origin/master' into 4.3.4
Conflicts:
src/server/authserver/Main.cpp
src/server/authserver/Realms/RealmList.cpp
src/server/authserver/Realms/RealmList.h
src/server/authserver/Server/AuthSession.cpp
src/server/authserver/Server/AuthSocket.h
src/server/authserver/Server/RealmAcceptor.h
src/server/game/Accounts/AccountMgr.h
src/server/game/Achievements/AchievementMgr.cpp
src/server/game/Achievements/AchievementMgr.h
src/server/game/Battlegrounds/ArenaTeamMgr.cpp
src/server/game/Conditions/ConditionMgr.cpp
src/server/game/DungeonFinding/LFGMgr.h
src/server/game/Entities/Object/Object.h
src/server/game/Entities/Player/Player.cpp
src/server/game/Entities/Player/Player.h
src/server/game/Entities/Unit/Unit.cpp
src/server/game/Handlers/BattleGroundHandler.cpp
src/server/game/Movement/Spline/MoveSplineFlag.h
src/server/game/Quests/QuestDef.cpp
src/server/game/Quests/QuestDef.h
src/server/game/Server/WorldSession.cpp
src/server/game/Server/WorldSession.h
src/server/game/Server/WorldSocket.cpp
src/server/game/Server/WorldSocket.h
src/server/game/Spells/Spell.cpp
src/server/scripts/Commands/cs_debug.cpp
src/server/scripts/OutdoorPvP/OutdoorPvPEP.cpp
src/server/scripts/Spells/spell_mage.cpp
src/server/scripts/Spells/spell_rogue.cpp
src/server/scripts/Spells/spell_shaman.cpp
src/server/scripts/Spells/spell_warrior.cpp
src/server/shared/Cryptography/BigNumber.h
src/server/worldserver/RemoteAccess/RASocket.cpp
src/server/worldserver/worldserver.conf.dist
Diffstat (limited to 'src/server/worldserver/RemoteAccess')
| -rw-r--r-- | src/server/worldserver/RemoteAccess/RARunnable.cpp | 84 | ||||
| -rw-r--r-- | src/server/worldserver/RemoteAccess/RARunnable.h | 43 | ||||
| -rw-r--r-- | src/server/worldserver/RemoteAccess/RASession.cpp | 222 | ||||
| -rw-r--r-- | src/server/worldserver/RemoteAccess/RASession.h | 63 | ||||
| -rw-r--r-- | src/server/worldserver/RemoteAccess/RASocket.cpp | 424 | ||||
| -rw-r--r-- | src/server/worldserver/RemoteAccess/RASocket.h | 64 |
6 files changed, 285 insertions, 615 deletions
diff --git a/src/server/worldserver/RemoteAccess/RARunnable.cpp b/src/server/worldserver/RemoteAccess/RARunnable.cpp deleted file mode 100644 index 44b07163294..00000000000 --- a/src/server/worldserver/RemoteAccess/RARunnable.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** \file - \ingroup Trinityd - */ - -#include "Common.h" -#include "Config.h" -#include "Log.h" -#include "RARunnable.h" -#include "World.h" - -#include <ace/Reactor_Impl.h> -#include <ace/TP_Reactor.h> -#include <ace/Dev_Poll_Reactor.h> -#include <ace/Acceptor.h> -#include <ace/SOCK_Acceptor.h> - -#include "RASocket.h" - -RARunnable::RARunnable() -{ - ACE_Reactor_Impl* imp; - -#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) - imp = new ACE_Dev_Poll_Reactor(); - imp->max_notify_iterations (128); - imp->restart (1); -#else - imp = new ACE_TP_Reactor(); - imp->max_notify_iterations (128); -#endif - - m_Reactor = new ACE_Reactor (imp, 1); -} - -RARunnable::~RARunnable() -{ - delete m_Reactor; -} - -void RARunnable::run() -{ - if (!sConfigMgr->GetBoolDefault("Ra.Enable", false)) - return; - - ACE_Acceptor<RASocket, ACE_SOCK_ACCEPTOR> acceptor; - - uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443)); - std::string stringIp = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0"); - ACE_INET_Addr listenAddress(raPort, stringIp.c_str()); - - if (acceptor.open(listenAddress, m_Reactor) == -1) - { - TC_LOG_ERROR("server.worldserver", "Trinity RA can not bind to port %d on %s", raPort, stringIp.c_str()); - return; - } - - TC_LOG_INFO("server.worldserver", "Starting Trinity RA on port %d on %s", raPort, stringIp.c_str()); - - while (!World::IsStopped()) - { - ACE_Time_Value interval(0, 100000); - if (m_Reactor->run_reactor_event_loop(interval) == -1) - break; - } - - TC_LOG_DEBUG("server.worldserver", "Trinity RA thread exiting"); -} diff --git a/src/server/worldserver/RemoteAccess/RARunnable.h b/src/server/worldserver/RemoteAccess/RARunnable.h deleted file mode 100644 index 540ac762f30..00000000000 --- a/src/server/worldserver/RemoteAccess/RARunnable.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef _TRINITY_RARUNNABLE_H_ -#define _TRINITY_RARUNNABLE_H_ - -#include "Common.h" - -#include <ace/Reactor.h> - -class RARunnable : public ACE_Based::Runnable -{ -public: - RARunnable(); - virtual ~RARunnable(); - void run() override; - -private: - ACE_Reactor* m_Reactor; - -}; - -#endif /* _TRINITY_RARUNNABLE_H_ */ - -/// @} diff --git a/src/server/worldserver/RemoteAccess/RASession.cpp b/src/server/worldserver/RemoteAccess/RASession.cpp new file mode 100644 index 00000000000..846a4eb39e3 --- /dev/null +++ b/src/server/worldserver/RemoteAccess/RASession.cpp @@ -0,0 +1,222 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <memory> +#include <boost/asio/write.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/array.hpp> +#include "RASession.h" +#include "AccountMgr.h" +#include "Log.h" +#include "DatabaseEnv.h" +#include "World.h" +#include "Config.h" + +using boost::asio::ip::tcp; + +void RASession::Start() +{ + boost::asio::socket_base::bytes_readable command(true); + _socket.io_control(command); + std::size_t bytes_readable = command.get(); + + // Check if there are bytes available, if they are, then the client is requesting the negotiation + if (bytes_readable > 0) + { + // Handle subnegotiation + boost::array<char, 1024> buf; + _socket.read_some(boost::asio::buffer(buf)); + + // Send the end-of-negotiation packet + uint8 const reply[2] = { 0xFF, 0xF0 }; + _socket.write_some(boost::asio::buffer(reply)); + } + + Send("Authentication Required\r\n"); + Send("Username: "); + + std::string username = ReadString(); + + if (username.empty()) + return; + + TC_LOG_INFO("commands.ra", "Accepting RA connection from user %s (IP: %s)", username.c_str(), GetRemoteIpAddress().c_str()); + + Send("Password: "); + + std::string password = ReadString(); + if (password.empty()) + return; + + if (!CheckAccessLevel(username) || !CheckPassword(username, password)) + { + Send("Authentication failed\r\n"); + _socket.close(); + return; + } + + TC_LOG_INFO("commands.ra", "User %s (IP: %s) authenticated correctly to RA", username.c_str(), GetRemoteIpAddress().c_str()); + + // Authentication successful, send the motd + Send(std::string(std::string(sWorld->GetMotd()) + "\r\n").c_str()); + + // Read commands + for (;;) + { + Send("TC>"); + std::string command = ReadString(); + + if (ProcessCommand(command)) + break; + } + + _socket.close(); +} + +int RASession::Send(const char* data) +{ + std::ostream os(&_writeBuffer); + os << data; + size_t written = _socket.send(_writeBuffer.data()); + _writeBuffer.consume(written); + return written; +} + +std::string RASession::ReadString() +{ + boost::system::error_code error; + size_t read = boost::asio::read_until(_socket, _readBuffer, "\r\n", error); + if (!read) + { + _socket.close(); + return ""; + } + + std::string line; + std::istream is(&_readBuffer); + std::getline(is, line); + + if (*line.rbegin() == '\r') + line.erase(line.length() - 1); + + return line; +} + +bool RASession::CheckAccessLevel(const std::string& user) +{ + std::string safeUser = user; + + AccountMgr::normalizeString(safeUser); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); + stmt->setString(0, safeUser); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + if (!result) + { + TC_LOG_INFO("commands.ra", "User %s does not exist in database", user.c_str()); + return false; + } + + Field* fields = result->Fetch(); + + if (fields[1].GetUInt8() < sConfigMgr->GetIntDefault("RA.MinLevel", 3)) + { + TC_LOG_INFO("commands.ra", "User %s has no privilege to login", user.c_str()); + return false; + } + else if (fields[2].GetInt32() != -1) + { + TC_LOG_INFO("commands.ra", "User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str()); + return false; + } + + return true; +} + +bool RASession::CheckPassword(const std::string& user, const std::string& pass) +{ + std::string safe_user = user; + std::transform(safe_user.begin(), safe_user.end(), safe_user.begin(), ::toupper); + AccountMgr::normalizeString(safe_user); + + std::string safe_pass = pass; + AccountMgr::normalizeString(safe_pass); + std::transform(safe_pass.begin(), safe_pass.end(), safe_pass.begin(), ::toupper); + + std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME); + + stmt->setString(0, safe_user); + stmt->setString(1, hash); + + PreparedQueryResult result = LoginDatabase.Query(stmt); + + if (!result) + { + TC_LOG_INFO("commands.ra", "Wrong password for user: %s", user.c_str()); + return false; + } + + return true; +} + +bool RASession::ProcessCommand(std::string& command) +{ + if (command.length() == 0) + return true; + + TC_LOG_INFO("commands.ra", "Received command: %s", command.c_str()); + + // handle quit, exit and logout commands to terminate connection + if (command == "quit" || command == "exit" || command == "logout") + { + Send("Bye\r\n"); + return true; + } + + // Obtain a new promise per command + if (_commandExecuting != nullptr) + delete _commandExecuting; + + _commandExecuting = new std::promise<void>(); + + CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASession::CommandPrint, &RASession::CommandFinished); + sWorld->QueueCliCommand(cmd); + + // Wait for the command to finish + _commandExecuting->get_future().wait(); + + return false; +} + +void RASession::CommandPrint(void* callbackArg, const char* text) +{ + if (!text || !*text) + return; + + RASession* session = static_cast<RASession*>(callbackArg); + session->Send(text); +} + +void RASession::CommandFinished(void* callbackArg, bool /*success*/) +{ + RASession* session = static_cast<RASession*>(callbackArg); + session->_commandExecuting->set_value(); +} diff --git a/src/server/worldserver/RemoteAccess/RASession.h b/src/server/worldserver/RemoteAccess/RASession.h new file mode 100644 index 00000000000..61156a0fa53 --- /dev/null +++ b/src/server/worldserver/RemoteAccess/RASession.h @@ -0,0 +1,63 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __RASESSION_H__ +#define __RASESSION_H__ + +#include <memory> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/streambuf.hpp> +#include "Common.h" + +#include <future> + +using boost::asio::ip::tcp; + +const size_t bufferSize = 4096; + +#define BUFFER_SIZE 4096 + +class RASession : public std::enable_shared_from_this <RASession> +{ +public: + RASession(tcp::socket&& socket) : _socket(std::move(socket)), _commandExecuting(nullptr) + { + } + + void Start(); + + const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); } + unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); } + +private: + int Send(const char* data); + std::string ReadString(); + bool CheckAccessLevel(const std::string& user); + bool CheckPassword(const std::string& user, const std::string& pass); + bool ProcessCommand(std::string& command); + + static void CommandPrint(void* callbackArg, const char* text); + static void CommandFinished(void* callbackArg, bool); + + tcp::socket _socket; + boost::asio::streambuf _readBuffer; + boost::asio::streambuf _writeBuffer; + std::promise<void>* _commandExecuting; +}; + +#endif diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp deleted file mode 100644 index f2c7a8e0f02..00000000000 --- a/src/server/worldserver/RemoteAccess/RASocket.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** \file - \ingroup Trinityd -*/ - -#include "Common.h" -#include "Configuration/Config.h" -#include "Database/DatabaseEnv.h" -#include "AccountMgr.h" -#include "Log.h" -#include "RASocket.h" -#include "Util.h" -#include "World.h" -#include "SHA1.h" - -RASocket::RASocket() -{ - _minLevel = uint8(sConfigMgr->GetIntDefault("RA.MinLevel", 3)); - _commandExecuting = false; -} - -int RASocket::open(void *) -{ - ACE_INET_Addr remoteAddress; - - if (peer().get_remote_addr(remoteAddress) == -1) - { - TC_LOG_ERROR("server.worldserver", "RASocket::open: peer().get_remote_addr error is %s", ACE_OS::strerror(errno)); - return -1; - } - - TC_LOG_INFO("commands.ra", "Incoming connection from %s", remoteAddress.get_host_addr()); - - return activate(); -} - -int RASocket::handle_close(ACE_HANDLE /*handle*/, ACE_Reactor_Mask /*mask*/) -{ - TC_LOG_INFO("commands.ra", "Closing connection"); - peer().close_reader(); - wait(); - // While the above wait() will wait for the ::svc() to finish, it will not wait for the async event - // RASocket::commandfinished to be completed. Calling destroy() before the latter function ends - // will lead to using a freed pointer -> crash. - while (_commandExecuting.value()) - ACE_OS::sleep(1); - - destroy(); - return 0; -} - -int RASocket::send(const std::string& line) -{ -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send(line.c_str(), line.length(), MSG_NOSIGNAL); -#else - ssize_t n = peer().send(line.c_str(), line.length()); -#endif // MSG_NOSIGNAL - - return n == ssize_t(line.length()) ? 0 : -1; -} - -int RASocket::recv_line(ACE_Message_Block& buffer) -{ - char byte; - for (;;) - { - ssize_t n = peer().recv(&byte, sizeof(byte)); - - if (n < 0) - return -1; - - if (n == 0) - { - // EOF, connection was closed - errno = ECONNRESET; - return -1; - } - - ACE_ASSERT(n == sizeof(byte)); - - if (byte == '\n') - break; - else if (byte == '\r') /* Ignore CR */ - continue; - else if (buffer.copy(&byte, sizeof(byte)) == -1) - return -1; - } - - const char nullTerm = '\0'; - if (buffer.copy(&nullTerm, sizeof(nullTerm)) == -1) - return -1; - - return 0; -} - -int RASocket::recv_line(std::string& out_line) -{ - char buf[4096]; - - ACE_Data_Block db(sizeof (buf), - ACE_Message_Block::MB_DATA, - buf, - 0, - 0, - ACE_Message_Block::DONT_DELETE, - 0); - - ACE_Message_Block message_block(&db, - ACE_Message_Block::DONT_DELETE, - 0); - - if (recv_line(message_block) == -1) - { - TC_LOG_DEBUG("commands.ra", "Recv error %s", ACE_OS::strerror(errno)); - return -1; - } - - out_line = message_block.rd_ptr(); - - return 0; -} - -int RASocket::process_command(const std::string& command) -{ - if (command.length() == 0) - return 0; - - TC_LOG_INFO("commands.ra", "Received command: %s", command.c_str()); - - // handle quit, exit and logout commands to terminate connection - if (command == "quit" || command == "exit" || command == "logout") { - (void) send("Bye\r\n"); - return -1; - } - - _commandExecuting = true; - CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished); - sWorld->QueueCliCommand(cmd); - - // wait for result - ACE_Message_Block* mb; - for (;;) - { - if (getq(mb) == -1) - return -1; - - if (mb->msg_type() == ACE_Message_Block::MB_BREAK) - { - mb->release(); - break; - } - - if (send(std::string(mb->rd_ptr(), mb->length())) == -1) - { - mb->release(); - return -1; - } - - mb->release(); - } - - return 0; -} - -int RASocket::check_access_level(const std::string& user) -{ - std::string safeUser = user; - - Utf8ToUpperOnlyLatin(safeUser); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); - stmt->setString(0, safeUser); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - if (!result) - { - TC_LOG_INFO("commands.ra", "User %s does not exist in database", user.c_str()); - return -1; - } - - Field* fields = result->Fetch(); - - if (fields[1].GetUInt8() < _minLevel) - { - TC_LOG_INFO("commands.ra", "User %s has no privilege to login", user.c_str()); - return -1; - } - else if (fields[2].GetInt32() != -1) - { - TC_LOG_INFO("commands.ra", "User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str()); - return -1; - } - - return 0; -} - -int RASocket::check_password(const std::string& user, const std::string& pass) -{ - std::string safe_user = user; - Utf8ToUpperOnlyLatin(safe_user); - - std::string safe_pass = pass; - Utf8ToUpperOnlyLatin(safe_pass); - - std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME); - - stmt->setString(0, safe_user); - stmt->setString(1, hash); - - PreparedQueryResult result = LoginDatabase.Query(stmt); - - if (!result) - { - TC_LOG_INFO("commands.ra", "Wrong password for user: %s", user.c_str()); - return -1; - } - - return 0; -} - -int RASocket::authenticate() -{ - if (send(std::string("Username: ")) == -1) - return -1; - - std::string user; - if (recv_line(user) == -1) - return -1; - - if (send(std::string("Password: ")) == -1) - return -1; - - std::string pass; - if (recv_line(pass) == -1) - return -1; - - TC_LOG_INFO("commands.ra", "Login attempt for user: %s", user.c_str()); - - if (check_access_level(user) == -1) - return -1; - - if (check_password(user, pass) == -1) - return -1; - - TC_LOG_INFO("commands.ra", "User login: %s", user.c_str()); - - return 0; -} - - -int RASocket::subnegotiate() -{ - char buf[1024]; - - ACE_Data_Block db(sizeof (buf), - ACE_Message_Block::MB_DATA, - buf, - 0, - 0, - ACE_Message_Block::DONT_DELETE, - 0); - - ACE_Message_Block message_block(&db, - ACE_Message_Block::DONT_DELETE, - 0); - - const size_t recv_size = message_block.space(); - - // Wait a maximum of 1000ms for negotiation packet - not all telnet clients may send it - ACE_Time_Value waitTime = ACE_Time_Value(1); - const ssize_t n = peer().recv(message_block.wr_ptr(), - recv_size, &waitTime); - - if (n <= 0) - return int(n); - - if (n >= 1024) - { - TC_LOG_DEBUG("commands.ra", "RASocket::subnegotiate: allocated buffer 1024 bytes was too small for negotiation packet, size: %u", uint32(n)); - return -1; - } - - buf[n] = '\0'; - - #ifdef _DEBUG - for (uint8 i = 0; i < n; ) - { - uint8 iac = buf[i]; - if (iac == 0xFF) // "Interpret as Command" (IAC) - { - uint8 command = buf[++i]; - std::stringstream ss; - switch (command) - { - case 0xFB: // WILL - ss << "WILL "; - break; - case 0xFC: // WON'T - ss << "WON'T "; - break; - case 0xFD: // DO - ss << "DO "; - break; - case 0xFE: // DON'T - ss << "DON'T "; - break; - default: - return -1; // not allowed - } - - uint8 param = buf[++i]; - ss << uint32(param); - TC_LOG_DEBUG("commands.ra", ss.str().c_str()); - } - ++i; - } - #endif - - //! Just send back end of subnegotiation packet - uint8 const reply[2] = {0xFF, 0xF0}; - -#ifdef MSG_NOSIGNAL - return int(peer().send(reply, 2, MSG_NOSIGNAL)); -#else - return int(peer().send(reply, 2)); -#endif // MSG_NOSIGNAL -} - -int RASocket::svc(void) -{ - //! Subnegotiation may differ per client - do not react on it - subnegotiate(); - - if (send("Authentication required\r\n") == -1) - return -1; - - if (authenticate() == -1) - { - (void) send("Authentication failed\r\n"); - return -1; - } - - // send motd - if (send(std::string(sWorld->GetMotd()) + "\r\n") == -1) - return -1; - - for (;;) - { - // show prompt - if (send("TC> ") == -1) - return -1; - - std::string line; - - if (recv_line(line) == -1) - return -1; - - if (process_command(line) == -1) - return -1; - } - - return 0; -} - -void RASocket::zprint(void* callbackArg, const char * szText) -{ - if (!szText || !callbackArg) - return; - - RASocket* socket = static_cast<RASocket*>(callbackArg); - size_t sz = strlen(szText); - - ACE_Message_Block* mb = new ACE_Message_Block(sz); - mb->copy(szText, sz); - - ACE_Time_Value tv = ACE_Time_Value::zero; - if (socket->putq(mb, &tv) == -1) - { - TC_LOG_DEBUG("commands.ra", "Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno)); - mb->release(); - } -} - -void RASocket::commandFinished(void* callbackArg, bool /*success*/) -{ - if (!callbackArg) - return; - - RASocket* socket = static_cast<RASocket*>(callbackArg); - - ACE_Message_Block* mb = new ACE_Message_Block(); - - mb->msg_type(ACE_Message_Block::MB_BREAK); - - // the message is 0 size control message to tell that command output is finished - // hence we don't put timeout, because it shouldn't increase queue size and shouldn't block - if (socket->putq(mb->duplicate()) == -1) - // getting here is bad, command can't be marked as complete - TC_LOG_DEBUG("commands.ra", "Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno)); - - mb->release(); - - socket->_commandExecuting = false; -} diff --git a/src/server/worldserver/RemoteAccess/RASocket.h b/src/server/worldserver/RemoteAccess/RASocket.h deleted file mode 100644 index 2cbb14b3578..00000000000 --- a/src/server/worldserver/RemoteAccess/RASocket.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef _RASOCKET_H -#define _RASOCKET_H - -#include "Common.h" - -#include <ace/Synch_Traits.h> -#include <ace/Svc_Handler.h> -#include <ace/SOCK_Stream.h> -#include <ace/SOCK_Acceptor.h> - -/// Remote Administration socket -class RASocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> -{ - public: - RASocket(); - virtual ~RASocket() { } - - virtual int svc() override; - virtual int open(void* = 0) override; - virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK) override; - - private: - int recv_line(std::string& outLine); - int recv_line(ACE_Message_Block& buffer); - int process_command(const std::string& command); - int authenticate(); - int subnegotiate(); ///< Used by telnet protocol RFC 854 / 855 - int check_access_level(const std::string& user); - int check_password(const std::string& user, const std::string& pass); - int send(const std::string& line); - - static void zprint(void* callbackArg, const char* szText); - static void commandFinished(void* callbackArg, bool success); - - private: - uint8 _minLevel; ///< Minimum security level required to connect - ACE_Atomic_Op<ACE_Thread_Mutex, bool> _commandExecuting; -}; - -#endif - -/// @} |
