AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
RASession Class Reference

#include "RASession.h"

Inheritance diagram for RASession:

Public Member Functions

 RASession (tcp::socket &&socket)
 
void Start ()
 
const std::string GetRemoteIpAddress () const
 
unsigned short GetRemotePort () const
 

Private Member Functions

int Send (std::string_view 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 Private Member Functions

static void CommandPrint (void *callbackArg, std::string_view text)
 
static void CommandFinished (void *callbackArg, bool)
 

Private Attributes

tcp::socket _socket
 
boost::asio::streambuf _readBuffer
 
boost::asio::streambuf _writeBuffer
 
std::promise< void > * _commandExecuting
 

Detailed Description

Constructor & Destructor Documentation

◆ RASession()

RASession::RASession ( tcp::socket &&  socket)
inline
32 :
33 _socket(std::move(socket)), _commandExecuting(nullptr) { }
std::promise< void > * _commandExecuting
Definition: RASession.h:53
tcp::socket _socket
Definition: RASession.h:50

Member Function Documentation

◆ CheckAccessLevel()

bool RASession::CheckAccessLevel ( const std::string &  user)
private
124{
125 std::string safeUser = user;
126
127 Utf8ToUpperOnlyLatin(safeUser);
128
129 auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS);
130 stmt->SetData(0, safeUser);
131
132 PreparedQueryResult result = LoginDatabase.Query(stmt);
133 if (!result)
134 {
135 LOG_INFO("commands.ra", "User {} does not exist in database", user);
136 return false;
137 }
138
139 Field* fields = result->Fetch();
140
141 if (fields[1].Get<uint8>() < sConfigMgr->GetOption<int32>("Ra.MinLevel", 3))
142 {
143 LOG_INFO("commands.ra", "User {} has no privilege to login", user);
144 return false;
145 }
146 else if (fields[2].Get<int32>() != -1)
147 {
148 LOG_INFO("commands.ra", "User {} has to be assigned on all realms (with RealmID = '-1')", user);
149 return false;
150 }
151
152 return true;
153}
#define LOG_INFO(filterType__,...)
Definition: Log.h:165
bool Utf8ToUpperOnlyLatin(std::string &utf8String)
Definition: Util.cpp:532
#define sConfigMgr
Definition: Config.h:74
std::int32_t int32
Definition: Define.h:103
@ LOGIN_SEL_ACCOUNT_ACCESS
Definition: LoginDatabase.h:93
std::shared_ptr< PreparedResultSet > PreparedQueryResult
Definition: DatabaseEnvFwd.h:45
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
Class used to access individual fields of database query result.
Definition: Field.h:98

References LOG_INFO, LOGIN_SEL_ACCOUNT_ACCESS, LoginDatabase, sConfigMgr, and Utf8ToUpperOnlyLatin().

Referenced by Start().

◆ CheckPassword()

bool RASession::CheckPassword ( const std::string &  user,
const std::string &  pass 
)
private
156{
157 std::string safe_user = user;
158 std::transform(safe_user.begin(), safe_user.end(), safe_user.begin(), ::toupper);
159 Utf8ToUpperOnlyLatin(safe_user);
160
161 std::string safe_pass = pass;
162 Utf8ToUpperOnlyLatin(safe_pass);
163 std::transform(safe_pass.begin(), safe_pass.end(), safe_pass.begin(), ::toupper);
164
165 auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME);
166
167 stmt->SetData(0, safe_user);
168
169 if (PreparedQueryResult result = LoginDatabase.Query(stmt))
170 {
173
174 if (Acore::Crypto::SRP6::CheckLogin(safe_user, safe_pass, salt, verifier))
175 return true;
176 }
177
178 LOG_INFO("commands.ra", "Wrong password for user: {}", user);
179 return false;
180}
@ LOGIN_SEL_CHECK_PASSWORD_BY_NAME
Definition: LoginDatabase.h:87
std::vector< uint8 > Binary
Definition: Field.h:40
static constexpr std::size_t VERIFIER_LENGTH
Definition: SRP6.h:34
std::array< uint8, SALT_LENGTH > Salt
Definition: SRP6.h:32
static bool CheckLogin(std::string const &username, std::string const &password, Salt const &salt, Verifier const &verifier)
Definition: SRP6.h:47
std::array< uint8, VERIFIER_LENGTH > Verifier
Definition: SRP6.h:35
static constexpr std::size_t SALT_LENGTH
Definition: SRP6.h:31

References Acore::Crypto::SRP6::CheckLogin(), LOG_INFO, LOGIN_SEL_CHECK_PASSWORD_BY_NAME, LoginDatabase, Acore::Crypto::SRP6::SALT_LENGTH, Utf8ToUpperOnlyLatin(), and Acore::Crypto::SRP6::VERIFIER_LENGTH.

Referenced by Start().

◆ CommandFinished()

void RASession::CommandFinished ( void *  callbackArg,
bool   
)
staticprivate
221{
222 RASession* session = static_cast<RASession*>(callbackArg);
223 session->_commandExecuting->set_value();
224}
Definition: RASession.h:30

References _commandExecuting.

Referenced by ProcessCommand().

◆ CommandPrint()

void RASession::CommandPrint ( void *  callbackArg,
std::string_view  text 
)
staticprivate
210{
211 if (text.empty())
212 {
213 return;
214 }
215
216 RASession* session = static_cast<RASession*>(callbackArg);
217 session->Send(text);
218}
int Send(std::string_view data)
Definition: RASession.cpp:94

References Send().

Referenced by ProcessCommand().

◆ GetRemoteIpAddress()

const std::string RASession::GetRemoteIpAddress ( ) const
inline
37{ return _socket.remote_endpoint().address().to_string(); }

References _socket.

Referenced by Start().

◆ GetRemotePort()

unsigned short RASession::GetRemotePort ( ) const
inline
38{ return _socket.remote_endpoint().port(); }

References _socket.

◆ ProcessCommand()

bool RASession::ProcessCommand ( std::string &  command)
private
183{
184 if (command.length() == 0)
185 return true;
186
187 LOG_INFO("commands.ra", "Received command: {}", command);
188
189 // handle quit, exit and logout commands to terminate connection
190 if (command == "quit" || command == "exit" || command == "logout")
191 {
192 Send("Bye\r\n");
193 return true;
194 }
195
196 // Obtain a new promise per command
197 delete _commandExecuting;
198 _commandExecuting = new std::promise<void>();
199
201 sWorld->QueueCliCommand(cmd);
202
203 // Wait for the command to finish
204 _commandExecuting->get_future().wait();
205
206 return false;
207}
#define sWorld
Definition: World.h:443
static void CommandFinished(void *callbackArg, bool)
Definition: RASession.cpp:220
static void CommandPrint(void *callbackArg, std::string_view text)
Definition: RASession.cpp:209
Storage class for commands issued for delayed execution.
Definition: IWorld.h:34

References _commandExecuting, CommandFinished(), CommandPrint(), LOG_INFO, Send(), and sWorld.

Referenced by Start().

◆ ReadString()

std::string RASession::ReadString ( )
private
104{
105 boost::system::error_code error;
106 std::size_t read = boost::asio::read_until(_socket, _readBuffer, "\r\n", error);
107 if (!read)
108 {
109 _socket.close();
110 return "";
111 }
112
113 std::string line;
114 std::istream is(&_readBuffer);
115 std::getline(is, line);
116
117 if (*line.rbegin() == '\r')
118 line.erase(line.length() - 1);
119
120 return line;
121}
boost::asio::streambuf _readBuffer
Definition: RASession.h:51

References _readBuffer, and _socket.

Referenced by Start().

◆ Send()

int RASession::Send ( std::string_view  data)
private
95{
96 std::ostream os(&_writeBuffer);
97 os << data;
98 std::size_t written = _socket.send(_writeBuffer.data());
99 _writeBuffer.consume(written);
100 return written;
101}
boost::asio::streambuf _writeBuffer
Definition: RASession.h:52

References _socket, and _writeBuffer.

Referenced by CommandPrint(), ProcessCommand(), and Start().

◆ Start()

void RASession::Start ( )
36{
37 // wait 1 second for active connections to send negotiation request
38 for (int counter = 0; counter < 10 && _socket.available() == 0; counter++)
39 std::this_thread::sleep_for(100ms);
40
41 // Check if there are bytes available, if they are, then the client is requesting the negotiation
42 if (_socket.available() > 0)
43 {
44 // Handle subnegotiation
45 char buf[1024] = { };
46 _socket.read_some(boost::asio::buffer(buf));
47
48 // Send the end-of-negotiation packet
49 uint8 const reply[2] = { 0xFF, 0xF0 };
50 _socket.write_some(boost::asio::buffer(reply));
51 }
52
53 Send("Authentication Required\r\n");
54 Send("Username: ");
55
56 std::string username = ReadString();
57
58 if (username.empty())
59 return;
60
61 LOG_INFO("commands.ra", "Accepting RA connection from user {} (IP: {})", username, GetRemoteIpAddress());
62
63 Send("Password: ");
64
65 std::string password = ReadString();
66 if (password.empty())
67 return;
68
69 if (!CheckAccessLevel(username) || !CheckPassword(username, password))
70 {
71 Send("Authentication failed\r\n");
72 _socket.close();
73 return;
74 }
75
76 LOG_INFO("commands.ra", "User {} (IP: {}) authenticated correctly to RA", username, GetRemoteIpAddress());
77
78 // Authentication successful, send the motd
79 Send(std::string(std::string(sMotdMgr->GetMotd(DEFAULT_LOCALE)) + "\r\n").c_str());
80
81 // Read commands
82 for (;;)
83 {
84 Send("AC>");
85 std::string command = ReadString();
86
87 if (ProcessCommand(command))
88 break;
89 }
90
91 _socket.close();
92}
#define DEFAULT_LOCALE
Definition: Common.h:79
std::uint8_t uint8
Definition: Define.h:109
#define sMotdMgr
Definition: MotdMgr.h:61
std::string ReadString()
Definition: RASession.cpp:103
bool CheckAccessLevel(const std::string &user)
Definition: RASession.cpp:123
bool CheckPassword(const std::string &user, const std::string &pass)
Definition: RASession.cpp:155
bool ProcessCommand(std::string &command)
Definition: RASession.cpp:182
const std::string GetRemoteIpAddress() const
Definition: RASession.h:37

References _socket, CheckAccessLevel(), CheckPassword(), DEFAULT_LOCALE, GetRemoteIpAddress(), LOG_INFO, ProcessCommand(), ReadString(), Send(), and sMotdMgr.

Member Data Documentation

◆ _commandExecuting

std::promise<void>* RASession::_commandExecuting
private

Referenced by CommandFinished(), and ProcessCommand().

◆ _readBuffer

boost::asio::streambuf RASession::_readBuffer
private

Referenced by ReadString().

◆ _socket

tcp::socket RASession::_socket
private

◆ _writeBuffer

boost::asio::streambuf RASession::_writeBuffer
private

Referenced by Send().