mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-05-02 10:39:20 +02:00
203 lines
5.2 KiB
C++
203 lines
5.2 KiB
C++
/**
|
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "otpch.h"
|
|
|
|
#include "protocollogin.h"
|
|
|
|
#include "outputmessage.h"
|
|
#include "tasks.h"
|
|
|
|
#include "configmanager.h"
|
|
#include "iologindata.h"
|
|
#include "ban.h"
|
|
#include "game.h"
|
|
|
|
extern ConfigManager g_config;
|
|
extern Game g_game;
|
|
|
|
void ProtocolLogin::disconnectClient(const std::string& message, uint16_t version)
|
|
{
|
|
auto output = OutputMessagePool::getOutputMessage();
|
|
|
|
output->addByte(version >= 1076 ? 0x0B : 0x0A);
|
|
output->addString(message);
|
|
send(output);
|
|
|
|
disconnect();
|
|
}
|
|
|
|
void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password, uint16_t version)
|
|
{
|
|
Account account;
|
|
if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
|
|
disconnectClient("Accountnumber or password is not correct.", version);
|
|
return;
|
|
}
|
|
|
|
auto output = OutputMessagePool::getOutputMessage();
|
|
|
|
//Update premium days
|
|
Game::updatePremium(account);
|
|
|
|
const std::string& motd = g_config.getString(ConfigManager::MOTD);
|
|
if (!motd.empty()) {
|
|
//Add MOTD
|
|
output->addByte(0x14);
|
|
|
|
std::ostringstream ss;
|
|
ss << g_game.getMotdNum() << "\n" << motd;
|
|
output->addString(ss.str());
|
|
}
|
|
|
|
//Add char list
|
|
output->addByte(0x64);
|
|
|
|
uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
|
|
output->addByte(size);
|
|
for (uint8_t i = 0; i < size; i++) {
|
|
output->addString(account.characters[i]);
|
|
output->addString(g_config.getString(ConfigManager::SERVER_NAME));
|
|
output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
|
|
output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
|
|
}
|
|
|
|
//Add premium days
|
|
if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
|
|
output->add<uint16_t>(0xFFFF);
|
|
}
|
|
else {
|
|
output->add<uint16_t>(account.premiumDays);
|
|
}
|
|
|
|
send(output);
|
|
|
|
disconnect();
|
|
}
|
|
|
|
|
|
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
|
|
{
|
|
if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
|
|
disconnect();
|
|
return;
|
|
}
|
|
|
|
msg.skipBytes(2); // client OS
|
|
|
|
uint16_t version = msg.get<uint16_t>();
|
|
if (version >= 971) {
|
|
msg.skipBytes(17);
|
|
}
|
|
else {
|
|
msg.skipBytes(12);
|
|
}
|
|
|
|
/*
|
|
* Skipped bytes:
|
|
* 4 bytes: protocolVersion
|
|
* 12 bytes: dat, spr, pic signatures (4 bytes each)
|
|
* 1 byte: 0
|
|
*/
|
|
|
|
if (version <= 760) {
|
|
std::ostringstream ss;
|
|
ss << "Only clients with protocol " << getClientVersionString(g_game.getClientVersion()) << " allowed!";
|
|
disconnectClient(ss.str(), version);
|
|
return;
|
|
}
|
|
|
|
if (!Protocol::RSA_decrypt(msg)) {
|
|
disconnect();
|
|
return;
|
|
}
|
|
|
|
uint32_t key[4];
|
|
key[0] = msg.get<uint32_t>();
|
|
key[1] = msg.get<uint32_t>();
|
|
key[2] = msg.get<uint32_t>();
|
|
key[3] = msg.get<uint32_t>();
|
|
enableXTEAEncryption();
|
|
setXTEAKey(key);
|
|
|
|
if (!isProtocolAllowed(version)) {
|
|
std::ostringstream ss;
|
|
ss << "Only clients with protocol " << getClientVersionString(g_game.getClientVersion()) << " allowed!";
|
|
disconnectClient(ss.str(), version);
|
|
return;
|
|
}
|
|
|
|
if (g_game.getGameState() == GAME_STATE_STARTUP) {
|
|
disconnectClient("Gameworld is starting up. Please wait.", version);
|
|
return;
|
|
}
|
|
|
|
if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
|
|
disconnectClient("Gameworld is under maintenance.\nPlease re-connect in a while.", version);
|
|
return;
|
|
}
|
|
|
|
BanInfo banInfo;
|
|
auto connection = getConnection();
|
|
if (!connection) {
|
|
return;
|
|
}
|
|
|
|
if (IOBan::isIpBanned(connection->getIP(), banInfo)) {
|
|
if (banInfo.reason.empty()) {
|
|
banInfo.reason = "(none)";
|
|
}
|
|
|
|
std::ostringstream ss;
|
|
ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
|
|
disconnectClient(ss.str(), version);
|
|
return;
|
|
}
|
|
|
|
uint32_t accountNumber = msg.get<uint32_t>();
|
|
if (!accountNumber) {
|
|
disconnectClient("Invalid account number.", version);
|
|
return;
|
|
}
|
|
|
|
std::string password = msg.getString();
|
|
if (password.empty()) {
|
|
disconnectClient("Invalid password.", version);
|
|
return;
|
|
}
|
|
|
|
auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
|
|
g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, version)));
|
|
}
|
|
|
|
|
|
bool ProtocolLogin::isProtocolAllowed(uint16_t version)
|
|
{
|
|
ClientVersion_t allowedClientVersion = g_game.getClientVersion();
|
|
|
|
if (allowedClientVersion == version)
|
|
{
|
|
return true;
|
|
}
|
|
else if (version == 781 && allowedClientVersion == CLIENT_VERSION_780) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} |