TrinityCore
Loading...
Searching...
No Matches
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 "IpAddress.h"
23#include "Log.h"
24#include "Util.h"
25#include "World.h"
26#include <boost/asio/buffer.hpp>
27#include <boost/asio/read_until.hpp>
28#include <memory>
29#include <thread>
30
32{
33 _socket.non_blocking(false);
34
35 // wait 1 second for active connections to send negotiation request
36 for (int counter = 0; counter < 10 && _socket.available() == 0; counter++)
37 std::this_thread::sleep_for(100ms);
38
39 // Check if there are bytes available, if they are, then the client is requesting the negotiation
40 if (_socket.available() > 0)
41 {
42 // Handle subnegotiation
43 char buf[1024] = { };
44 _socket.read_some(boost::asio::buffer(buf));
45
46 // Send the end-of-negotiation packet
47 uint8 const reply[2] = { 0xFF, 0xF0 };
48 _socket.write_some(boost::asio::buffer(reply));
49 }
50
51 Send("Authentication Required\r\n");
52 Send("Username: ");
53
54 std::string username = ReadString();
55
56 if (username.empty())
57 return;
58
59 TC_LOG_INFO("commands.ra", "Accepting RA connection from user {} (IP: {})", username, GetRemoteIpAddress());
60
61 Send("Password: ");
62
63 std::string password = ReadString();
64 if (password.empty())
65 return;
66
67 if (!CheckAccessLevel(username) || !AccountMgr::CheckPassword(username, password))
68 {
69 Send("Authentication failed\r\n");
70 _socket.close();
71 return;
72 }
73
74 TC_LOG_INFO("commands.ra", "User {} (IP: {}) authenticated correctly to RA", username, GetRemoteIpAddress());
75
76 // Authentication successful, send the motd
77 for (std::string const& line : sWorld->GetMotd())
78 Send(line.c_str());
79 Send("\r\n");
80
81 // Read commands
82 for (;;)
83 {
84 Send("TC>");
85 std::string command = ReadString();
86
87 if (ProcessCommand(command))
88 break;
89 }
90
91 _socket.close();
92}
93
94int RASession::Send(std::string_view data)
95{
96 std::ostream os(&_writeBuffer);
97 os << data;
98 size_t written = _socket.send(_writeBuffer.data());
99 _writeBuffer.consume(written);
100 return written;
101}
102
104{
105 boost::system::error_code error;
106 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}
122
123bool RASession::CheckAccessLevel(const std::string& user)
124{
125 std::string safeUser = user;
126
127 Utf8ToUpperOnlyLatin(safeUser);
128
130 stmt->setString(0, safeUser);
131 PreparedQueryResult result = LoginDatabase.Query(stmt);
132
133 if (!result)
134 {
135 TC_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].GetUInt8() < sConfigMgr->GetIntDefault("Ra.MinLevel", SEC_ADMINISTRATOR))
142 {
143 TC_LOG_INFO("commands.ra", "User {} has no privilege to login", user);
144 return false;
145 }
146 else if (fields[2].GetInt32() != -1)
147 {
148 TC_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}
154
155bool RASession::ProcessCommand(std::string& command)
156{
157 if (command.length() == 0)
158 return true;
159
160 TC_LOG_INFO("commands.ra", "Received command: {}", command);
161
162 // handle quit, exit and logout commands to terminate connection
163 if (command == "quit" || command == "exit" || command == "logout")
164 {
165 Send("Bye\r\n");
166 return true;
167 }
168
169 // Obtain a new promise per command
170 delete _commandExecuting;
171 _commandExecuting = new std::promise<void>();
172
174 sWorld->QueueCliCommand(cmd);
175
176 // Wait for the command to finish
177 _commandExecuting->get_future().wait();
178
179 return false;
180}
181
182void RASession::CommandPrint(void* callbackArg, std::string_view text)
183{
184 if (text.empty())
185 return;
186
187 RASession* session = static_cast<RASession*>(callbackArg);
188 session->Send(text);
189}
190
191void RASession::CommandFinished(void* callbackArg, bool /*success*/)
192{
193 RASession* session = static_cast<RASession*>(callbackArg);
194 session->_commandExecuting->set_value();
195}
@ SEC_ADMINISTRATOR
Definition Common.h:46
#define sConfigMgr
Definition Config.h:64
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
uint8_t uint8
Definition Define.h:156
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
@ LOGIN_SEL_ACCOUNT_ACCESS
bool Utf8ToUpperOnlyLatin(std::string &utf8String)
Definition Util.cpp:752
static bool CheckPassword(std::string username, std::string password)
Class used to access individual fields of database query result.
Definition Field.h:94
void setString(uint8 index, std::string &&value)
int Send(std::string_view data)
Definition RASession.cpp:94
static void CommandFinished(void *callbackArg, bool)
std::string ReadString()
bool CheckAccessLevel(const std::string &user)
std::promise< void > * _commandExecuting
Definition RASession.h:54
boost::asio::streambuf _writeBuffer
Definition RASession.h:53
boost::asio::streambuf _readBuffer
Definition RASession.h:52
Trinity::Net::IoContextTcpSocket _socket
Definition RASession.h:51
bool ProcessCommand(std::string &command)
static void CommandPrint(void *callbackArg, std::string_view text)
boost::asio::ip::address GetRemoteIpAddress() const
Definition RASession.h:39
void Start()
Definition RASession.cpp:31
#define sWorld
Definition World.h:916
Storage class for commands issued for delayed execution.
Definition World.h:534