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
34 :
35 _socket(std::move(socket)), _commandExecuting(nullptr) { }
std::promise< void > * _commandExecuting
Definition: RASession.h:55
tcp::socket _socket
Definition: RASession.h:52

Member Function Documentation

◆ CheckAccessLevel()

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

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
155{
156 std::string safe_user = user;
157 std::transform(safe_user.begin(), safe_user.end(), safe_user.begin(), ::toupper);
158 Utf8ToUpperOnlyLatin(safe_user);
159
160 std::string safe_pass = pass;
161 Utf8ToUpperOnlyLatin(safe_pass);
162 std::transform(safe_pass.begin(), safe_pass.end(), safe_pass.begin(), ::toupper);
163
164 auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME);
165
166 stmt->SetData(0, safe_user);
167
168 if (PreparedQueryResult result = LoginDatabase.Query(stmt))
169 {
172
173 if (Acore::Crypto::SRP6::CheckLogin(safe_user, safe_pass, salt, verifier))
174 return true;
175 }
176
177 LOG_INFO("commands.ra", "Wrong password for user: {}", user);
178 return false;
179}
std::vector< uint8 > Binary
Definition: Field.h:41
@ LOGIN_SEL_CHECK_PASSWORD_BY_NAME
Definition: LoginDatabase.h:86
static constexpr size_t SALT_LENGTH
Definition: SRP6.h:31
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
static constexpr size_t VERIFIER_LENGTH
Definition: SRP6.h:34
std::array< uint8, VERIFIER_LENGTH > Verifier
Definition: SRP6.h:35

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
220{
221 RASession* session = static_cast<RASession*>(callbackArg);
222 session->_commandExecuting->set_value();
223}
Definition: RASession.h:32

References _commandExecuting.

Referenced by ProcessCommand().

◆ CommandPrint()

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

References Send().

Referenced by ProcessCommand().

◆ GetRemoteIpAddress()

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

References _socket.

Referenced by Start().

◆ GetRemotePort()

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

References _socket.

◆ ProcessCommand()

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

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

Referenced by Start().

◆ ReadString()

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

References _readBuffer, and _socket.

Referenced by Start().

◆ Send()

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

References _socket, and _writeBuffer.

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

◆ Start()

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

References _socket, CheckAccessLevel(), CheckPassword(), 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().