19#include <boost/asio/buffer.hpp>
20#include <boost/asio/error.hpp>
21#include <boost/asio/read_until.hpp>
22#include <boost/asio/write.hpp>
23#include <boost/system/error_code.hpp>
30RASocket::RASocket(std::shared_ptr<Skyfire::Asio::IoContextExecutor> executor, std::unique_ptr<RASocketHandle> socket, std::string
const& remoteAddress) :
61 std::shared_ptr<RASocket> self = shared_from_this();
64 self->start_subnegotiation();
97 std::shared_ptr<RASocket> self = shared_from_this();
101 if (error || self->_subnegotiationDone)
104 self->_subnegotiationDone =
true;
105 self->_subnegotiationTimedOut =
true;
107 boost::system::error_code ignored;
108 self->_socket->cancel(ignored);
109 self->finish_subnegotiation();
113 [self](boost::system::error_code
const& error,
size_t transferredBytes)
115 self->handle_subnegotiation_read(error, transferredBytes);
137 if (transferredBytes == 0)
145 SF_LOG_DEBUG(
"commands.ra",
"RASocket::subnegotiate: allocated buffer 1024 bytes was too small for negotiation packet, size: %u",
uint32(transferredBytes));
151 for (
size_t i = 0; i < transferredBytes;)
156 if (i + 2 >= transferredBytes)
163 std::stringstream ss;
191 uint8 const reply[2] = { 0xFF, 0xF0 };
192 std::shared_ptr<RASocket> self = shared_from_this();
193 queue_write(std::string(
reinterpret_cast<char const*
>(reply),
sizeof(reply)), [self](
bool success)
196 self->finish_subnegotiation();
209 std::shared_ptr<RASocket> self = shared_from_this();
210 queue_write(
"Authentication required\r\n", [self](
bool success)
213 self->prompt_username();
221 std::shared_ptr<RASocket> self = shared_from_this();
230 self->async_read_line([self](
bool read, std::string line)
238 self->_user = std::move(line);
239 self->prompt_password();
246 std::shared_ptr<RASocket> self = shared_from_this();
255 self->async_read_line([self](
bool read, std::string line)
263 self->_pass = std::move(line);
264 self->handle_credentials();
275 std::shared_ptr<RASocket> self = shared_from_this();
276 queue_write(
"Authentication failed\r\n", [self](
bool)
285 std::shared_ptr<RASocket> self = shared_from_this();
289 self->prompt_command();
297 std::shared_ptr<RASocket> self = shared_from_this();
306 self->async_read_line([self](
bool read, std::string line)
314 self->handle_command(line);
327 SF_LOG_INFO(
"commands.ra",
"Received command: %s", command.c_str());
329 if (command ==
"quit" || command ==
"exit" || command ==
"logout")
331 std::shared_ptr<RASocket> self = shared_from_this();
350 std::queue<std::string> empty;
356 sWorld->QueueCliCommand(cmd);
382 std::shared_ptr<RASocket> self = shared_from_this();
384 [self](boost::system::error_code
const& error,
size_t)
386 self->handle_async_write(error);
396 callback = std::move(
_writeQueue.front().Callback);
422 callback(
false, std::string());
426 std::shared_ptr<RASocket> self = shared_from_this();
428 [self, callback = std::move(callback)](boost::system::error_code
const& error,
size_t transferredBytes)
mutable
430 self->handle_read_line(error, transferredBytes, std::move(callback));
438 callback(
false, std::string());
445 std::getline(input, line);
447 if (!line.empty() && line.back() ==
'\r')
450 callback(
true, std::move(line));
464 bool hasOutput =
false;
465 bool commandComplete =
false;
481 commandComplete =
true;
488 std::shared_ptr<RASocket> self = shared_from_this();
489 queue_write(std::move(output), [self](
bool success)
492 std::lock_guard<std::mutex> guard(self->_commandLock);
493 self->_commandOutputDrainInProgress =
false;
497 self->drain_command_output();
510 std::string safeUser = user;
520 SF_LOG_INFO(
"commands.ra",
"User %s does not exist in database", user.c_str());
524 Field* fields = result->Fetch();
528 SF_LOG_INFO(
"commands.ra",
"User %s has no privilege to login", user.c_str());
531 else if (fields[2].GetInt32() != -1)
533 SF_LOG_INFO(
"commands.ra",
"User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str());
542 std::string safe_user = user;
545 std::string safe_pass = pass;
560 SF_LOG_INFO(
"commands.ra",
"Wrong password for user: %s", user.c_str());
566 if (!szText || !callbackArg)
573 size_t sz = strlen(szText);
574 std::shared_ptr<RASocket> self;
577 std::lock_guard<std::mutex> guard(socket->
_commandLock);
583 self->_executor->Post([self]
585 self->drain_command_output();
595 std::shared_ptr<RASocket> self;
598 std::lock_guard<std::mutex> guard(socket->
_commandLock);
611 self->_executor->Post([self]
613 self->drain_command_output();
#define SF_LOG_DEBUG(filterType__,...)
#define SF_LOG_INFO(filterType__,...)
@ LOGIN_SEL_CHECK_PASSWORD_BY_NAME
@ LOGIN_SEL_ACCOUNT_ACCESS
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
static bool normalizeString(std::string &utf8String)
void setString(const uint8 index, const std::string &value)
void handle_async_write(boost::system::error_code const &error)
bool _commandOutputDrainInProgress
std::unique_ptr< RASocketHandle > _socket
void queue_write(std::string data, WriteCallback callback=WriteCallback())
boost::asio::streambuf _lineBuffer
void send_authentication_required()
std::function< void(bool, std::string)> ReadLineCallback
void async_read_line(ReadLineCallback callback)
std::string _remoteAddress
void start_command(std::string const &command)
void finish_subnegotiation()
std::shared_ptr< Skyfire::Asio::IoContextExecutor > _executor
uint8 _minLevel
Minimum security level required to connect.
RASocket(std::shared_ptr< Skyfire::Asio::IoContextExecutor > executor, std::unique_ptr< RASocketHandle > socket, std::string const &remoteAddress)
std::function< void(bool)> WriteCallback
void handle_subnegotiation_read(boost::system::error_code const &error, size_t transferredBytes)
boost::asio::steady_timer _subnegotiationTimer
int check_password(const std::string &user, const std::string &pass)
bool _subnegotiationTimedOut
void drain_command_output()
std::shared_ptr< RASocket > _commandSelf
std::atomic< bool > _commandExecuting
static void zprint(void *callbackArg, const char *szText)
int check_access_level(const std::string &user)
void handle_command(std::string const &command)
static void commandFinished(void *callbackArg, bool success)
std::array< char, 1024 > _subnegotiationBuffer
void handle_credentials()
void start_subnegotiation()
Used by telnet protocol RFC 854 / 855.
void handle_read_line(boost::system::error_code const &error, size_t transferredBytes, ReadLineCallback callback)
std::queue< std::string > _commandOutput
std::atomic< bool > _closed
std::deque< PendingWrite > _writeQueue
std::array< uint8, SALT_LENGTH > Salt
static bool CheckLogin(std::string const &username, std::string const &password, Salt const &salt, Verifier const &verifier)
std::array< uint8, VERIFIER_LENGTH > Verifier
static constexpr size_t VERIFIER_LENGTH
static constexpr size_t SALT_LENGTH
void CloseTcpSocket(boost::asio::ip::tcp::socket &socket)
void CancelTimer(Timer &timer)
LoginDatabaseWorkerPool LoginDatabase
Storage class for commands issued for delayed execution.