TrinityCore
RASession.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "RASession.h"
19#include "AccountMgr.h"
20#include "Config.h"
21#include "DatabaseEnv.h"
22#include "Log.h"
23#include "Util.h"
24#include "World.h"
25#include <boost/asio/buffer.hpp>
26#include <boost/asio/read_until.hpp>
27#include <memory>
28#include <thread>
29
31{
32 // wait 1 second for active connections to send negotiation request
33 for (int counter = 0; counter < 10 && _socket.available() == 0; counter++)
34 std::this_thread::sleep_for(std::chrono::milliseconds(100));
35
36 // Check if there are bytes available, if they are, then the client is requesting the negotiation
37 if (_socket.available() > 0)
38 {
39 // Handle subnegotiation
40 char buf[1024] = { };
41 _socket.read_some(boost::asio::buffer(buf));
42
43 // Send the end-of-negotiation packet
44 uint8 const reply[2] = { 0xFF, 0xF0 };
45 _socket.write_some(boost::asio::buffer(reply));
46 }
47
48 Send("Authentication Required\r\n");
49 Send("Username: ");
50
51 std::string username = ReadString();
52
53 if (username.empty())
54 return;
55
56 TC_LOG_INFO("commands.ra", "Accepting RA connection from user {} (IP: {})", username, GetRemoteIpAddress());
57
58 Send("Password: ");
59
60 std::string password = ReadString();
61 if (password.empty())
62 return;
63
64 if (!CheckAccessLevel(username) || !AccountMgr::CheckPassword(username, password))
65 {
66 Send("Authentication failed\r\n");
67 _socket.close();
68 return;
69 }
70
71 TC_LOG_INFO("commands.ra", "User {} (IP: {}) authenticated correctly to RA", username, GetRemoteIpAddress());
72
73 // Authentication successful, send the motd
74 for (std::string const& line : sWorld->GetMotd())
75 Send(line.c_str());
76 Send("\r\n");
77
78 // Read commands
79 for (;;)
80 {
81 Send("TC>");
82 std::string command = ReadString();
83
84 if (ProcessCommand(command))
85 break;
86 }
87
88 _socket.close();
89}
90
91int RASession::Send(std::string_view data)
92{
93 std::ostream os(&_writeBuffer);
94 os << data;
95 size_t written = _socket.send(_writeBuffer.data());
96 _writeBuffer.consume(written);
97 return written;
98}
99
101{
102 boost::system::error_code error;
103 size_t read = boost::asio::read_until(_socket, _readBuffer, "\r\n", error);
104 if (!read)
105 {
106 _socket.close();
107 return "";
108 }
109
110 std::string line;
111 std::istream is(&_readBuffer);
112 std::getline(is, line);
113
114 if (*line.rbegin() == '\r')
115 line.erase(line.length() - 1);
116
117 return line;
118}
119
120bool RASession::CheckAccessLevel(const std::string& user)
121{
122 std::string safeUser = user;
123
124 Utf8ToUpperOnlyLatin(safeUser);
125
127 stmt->setString(0, safeUser);
128 PreparedQueryResult result = LoginDatabase.Query(stmt);
129
130 if (!result)
131 {
132 TC_LOG_INFO("commands.ra", "User {} does not exist in database", user);
133 return false;
134 }
135
136 Field* fields = result->Fetch();
137
138 if (fields[1].GetUInt8() < sConfigMgr->GetIntDefault("Ra.MinLevel", SEC_ADMINISTRATOR))
139 {
140 TC_LOG_INFO("commands.ra", "User {} has no privilege to login", user);
141 return false;
142 }
143 else if (fields[2].GetInt32() != -1)
144 {
145 TC_LOG_INFO("commands.ra", "User {} has to be assigned on all realms (with RealmID = '-1')", user);
146 return false;
147 }
148
149 return true;
150}
151
152bool RASession::ProcessCommand(std::string& command)
153{
154 if (command.length() == 0)
155 return true;
156
157 TC_LOG_INFO("commands.ra", "Received command: {}", command);
158
159 // handle quit, exit and logout commands to terminate connection
160 if (command == "quit" || command == "exit" || command == "logout")
161 {
162 Send("Bye\r\n");
163 return true;
164 }
165
166 // Obtain a new promise per command
167 delete _commandExecuting;
168 _commandExecuting = new std::promise<void>();
169
171 sWorld->QueueCliCommand(cmd);
172
173 // Wait for the command to finish
174 _commandExecuting->get_future().wait();
175
176 return false;
177}
178
179void RASession::CommandPrint(void* callbackArg, std::string_view text)
180{
181 if (text.empty())
182 return;
183
184 RASession* session = static_cast<RASession*>(callbackArg);
185 session->Send(text);
186}
187
188void RASession::CommandFinished(void* callbackArg, bool /*success*/)
189{
190 RASession* session = static_cast<RASession*>(callbackArg);
191 session->_commandExecuting->set_value();
192}
@ SEC_ADMINISTRATOR
Definition: Common.h:43
#define sConfigMgr
Definition: Config.h:61
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
uint8_t uint8
Definition: Define.h:144
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
@ LOGIN_SEL_ACCOUNT_ACCESS
Definition: LoginDatabase.h:87
bool Utf8ToUpperOnlyLatin(std::string &utf8String)
Definition: Util.cpp:795
static bool CheckPassword(std::string username, std::string password)
Definition: AccountMgr.cpp:349
Class used to access individual fields of database query result.
Definition: Field.h:90
void setString(const uint8 index, const std::string &value)
int Send(std::string_view data)
Definition: RASession.cpp:91
boost::asio::ip::tcp::socket _socket
Definition: RASession.h:50
std::string GetRemoteIpAddress() const
Definition: RASession.h:38
static void CommandFinished(void *callbackArg, bool)
Definition: RASession.cpp:188
std::string ReadString()
Definition: RASession.cpp:100
bool CheckAccessLevel(const std::string &user)
Definition: RASession.cpp:120
std::promise< void > * _commandExecuting
Definition: RASession.h:53
boost::asio::streambuf _writeBuffer
Definition: RASession.h:52
boost::asio::streambuf _readBuffer
Definition: RASession.h:51
bool ProcessCommand(std::string &command)
Definition: RASession.cpp:152
static void CommandPrint(void *callbackArg, std::string_view text)
Definition: RASession.cpp:179
void Start()
Definition: RASession.cpp:30
#define sWorld
Definition: World.h:931
Storage class for commands issued for delayed execution.
Definition: World.h:542