Index: AccountHandler.h =================================================================== --- AccountHandler.h (révision 0) +++ AccountHandler.h (révision 0) @@ -0,0 +1,54 @@ +#include "Common.h" + +struct Account +{ + uint32 id; + uint8 security; + uint8 locale; + bool tbc; + bool banned; + bool locked; + std::string name; + std::string I; + std::string LastIp; +}; + +struct BanIp +{ + std::string Ip; +}; + +struct RealmCharacter +{ + uint32 realmId; + uint32 acctId; + uint8 numChars; +}; + +class AcctContainer +{ + public: + + AcctContainer(); + Account* FindAccountById(uint32 acctid); + Account* FindAccountByName(std::string name); + bool IpBan(std::string ClientIp); + void LoadAll(bool reloading); + void Initialize(); + void AddAccount(Account* account,uint32 id, uint8 security, uint8 locale, uint8 tbc, bool banned, uint8 locked, std::string name, std::string I, std::string lastip); + void AddCharacter(RealmCharacter* rcharacter, uint32 realmId, uint32 acctId, uint8 numChars); + void AddBan(BanIp* banip, std::string Ip){ banip->Ip = Ip; } + uint8 GetNumChar(uint32 realmId, uint32 accountId); + + private: + + typedef HM_NAMESPACE::hash_map AccountList; + typedef std::map IpBanList; + typedef HM_NAMESPACE::hash_map CharactersList; + + AccountList m_accounts; + IpBanList m_banips; + CharactersList m_characters; +}; + +#define AcctMgr MaNGOS::Singleton::Instance() Index: Main.cpp =================================================================== --- Main.cpp (révision 5150) +++ Main.cpp (copie de travail) @@ -31,6 +31,8 @@ #include "SystemConfig.h" #include "Util.h" +#include "AccountHandler.h" + #ifdef WIN32 #include "ServiceWin32.h" char serviceName[] = "realmd"; @@ -192,6 +194,10 @@ sLog.outError( "MaNGOS realmd can not bind to port %d", rmport ); return 1; } + + // Activate or not account caching system + if(sConfig.GetIntDefault("AccountCaching", 0) == 1) + AcctMgr.Initialize(); h.Add(&authListenSocket); Index: Makefile.am =================================================================== --- Makefile.am (révision 5150) +++ Makefile.am (copie de travail) @@ -27,7 +27,9 @@ AuthSocket.h \ Main.cpp \ RealmList.cpp \ - RealmList.h + RealmList.h \ + AccountHandler.cpp \ + AccountHandler.h ## Link realm list daemon against the shared library mangos_realmd_LDADD = ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la Index: AuthSocket.cpp =================================================================== --- AuthSocket.cpp (révision 5150) +++ AuthSocket.cpp (copie de travail) @@ -30,6 +30,9 @@ #include // needs for towupper #include #include "Auth/Sha1.h" +#include "AccountHandler.h" +#include "Config/ConfigEnv.h" +#include extern RealmList m_realmList; @@ -370,6 +373,8 @@ pkt << (uint8) AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; + if(sConfig.GetIntDefault("AccountCaching", 0) != 1) + { ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) dbRealmServer.Execute("DELETE FROM `ip_banned` WHERE `unbandate`<=UNIX_TIMESTAMP() AND `unbandate`<>`bandate`"); @@ -484,10 +489,100 @@ { pkt<< (uint8) REALM_AUTH_NO_MATCH; } - } - } //valid version + } + } + else + { + if(AcctMgr.IpBan(GetRemoteAddress())) + { + pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED; + } + else + { + Account* acct = AcctMgr.FindAccountByName(_safelogin); + + if(acct) + { + bool locked = false; + + if(acct->locked == 1) // if ip is locked + { + if ( strcmp(acct->LastIp.c_str(),GetRemoteAddress().c_str()) ) + { + pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED; + locked=true; + } + } + + if (!locked) + { + if(acct->banned) + { + pkt << (uint8) REALM_AUTH_ACCOUNT_BANNED; + } + else + { + ///- Get the password from the account table, upper it, and make the SRP6 calculation + std::string rI = acct->I; + _SetVSFields(rI); + b.SetRand(19 * 8); + BigNumber gmod=g.ModExp(b, N); + B = ((v * 3) + gmod) % N; + + if (B.GetNumBytes() < 32) + sLog.outDetail("Interesting, calculation of B in realmd is < 32."); + + ASSERT(gmod.GetNumBytes() <= 32); + + BigNumber unk3; + unk3.SetRand(16*8); + + ///- Fill the response packet with the result + pkt << (uint8)REALM_AUTH_SUCCESS; + pkt.append(B.AsByteArray(), B.GetNumBytes()); + pkt << (uint8)1; + pkt.append(g.AsByteArray(), 1); + pkt << (uint8)32; + pkt.append(N.AsByteArray(), 32); + pkt.append(s.AsByteArray(), s.GetNumBytes()); + pkt.append(unk3.AsByteArray(), 16); + pkt << (uint8)0; // Added in 1.12.x client branch + + uint8 secLevel = acct->security; + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + + // There isn't many differents locale so i think we can hardcode them all + + char charbuffer[3]; + charbuffer[0] = ch->country[3]; + charbuffer[1] = ch->country[2]; + charbuffer[2] = '\0'; + + if(strcmp (charbuffer,"fr") == 0) + _localization = 2; + else if(strcmp (charbuffer,"de") == 0) + _localization = 3; + else + _localization = 0; + + sLog.outString("Account Authed %u", acct->id); + + } + } + else + { + pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED; + } + } + else //no account + { + pkt<< (uint8) REALM_AUTH_NO_MATCH; + } + } + } + } //valid version else - ///
  • else + ///
  • else { ///- Check if we have the apropriate patch on the disk char tmp[64]; @@ -535,7 +630,7 @@ } /// SendBuf((char const*)pkt.contents(), pkt.size()); - return true; + return true; } /// Logon Proof command handler @@ -664,6 +759,11 @@ ///- Get the user id (else close the connection) // No SQL injection (escaped user name) + std::string rI; + uint32 id; + + if(sConfig.GetIntDefault("AccountCaching", 0) != 1) + { QueryResult *result = dbRealmServer.PQuery("SELECT `id`,`I` FROM `account` WHERE `username` = '%s'",_safelogin.c_str()); if(!result) { @@ -672,15 +772,29 @@ return false; } - uint32 id = (*result)[0].GetUInt32(); - std::string rI = (*result)[1].GetCppString(); + id = (*result)[0].GetUInt32(); + rI = (*result)[1].GetCppString(); delete result; + } + else + { + Account* acct = AcctMgr.FindAccountByName(_safelogin); + if(!acct) + { + SetCloseAndDelete(); + return false; + } + id = acct->id; + rI = acct->I; + } + ///- Update realm list if need m_realmList.UpdateIfNeed(); ///- Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; + pkt << (uint32) 0; pkt << (uint16) m_realmList.size(); RealmList::RealmMap::const_iterator i; @@ -688,16 +802,32 @@ { uint8 AmountOfCharacters; - // No SQL injection. id of realm is controlled by the database. - result = dbRealmServer.PQuery( "SELECT `numchars` FROM `realmcharacters` WHERE `realmid` = '%d' AND `acctid`='%u'",i->second.m_ID,id); - if( result ) - { - Field *fields = result->Fetch(); - AmountOfCharacters = fields[0].GetUInt8(); - delete result; - } - else - AmountOfCharacters = 0; + /*if(sConfig.GetIntDefault("AccountCaching", 0) != 1) + { + // No SQL injection. id of realm is controlled by the database.*/ + QueryResult* result = dbRealmServer.PQuery( "SELECT `numchars` FROM `realmcharacters` WHERE `realmid` = '%d' AND `acctid`='%u'",i->second.m_ID,id); + if( result ) + { + Field *fields = result->Fetch(); + AmountOfCharacters = fields[0].GetUInt8(); + delete result; + } + else + AmountOfCharacters = 0; + /*} + else + { + AmountOfCharacters = AcctMgr.GetNumChar(i->second.m_ID, id); + // Why client stay at connected at disconnect / reconnect if we don't wait 100 ms before sending realmlist ... Don't understand why this isn't needed at first connection... We doesn't have this problem before since + // Query take time so i think this was the thing who make this problem not appear ... + // EDIT : Client not seem to wait fixed delay, if there are many connections this 100 ms delay seem to be not good at all don't understand ... :/ + #ifdef WIN32 + sleep(100); + #else + ZThread::Thread::sleep(100); + #endif + }*/ + uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; Index: AccountHandler.cpp =================================================================== --- AccountHandler.cpp (révision 0) +++ AccountHandler.cpp (révision 0) @@ -0,0 +1,225 @@ +#include "Database/DatabaseEnv.h" +#include "Policies/SingletonImp.h" +#include "AccountHandler.h" +#include "ProgressBar.h" + +#ifdef DO_POSTGRESQL +extern DatabasePostgre dbRealmServer; +#else +extern DatabaseMysql dbRealmServer; +#endif + +INSTANTIATE_SINGLETON_1( AcctContainer); + +AcctContainer::AcctContainer() +{ + // +} + +void AcctContainer::Initialize() +{ + LoadAll(false); +} + +void AcctContainer::AddAccount(Account* account,uint32 id, uint8 security, uint8 locale, uint8 tbc, bool banned, uint8 locked, std::string name, std::string I, std::string lastip) +{ + account->id = id; + account->security = security; + account->locale = locale; + account->tbc = tbc; + account->banned = banned; + account->locked = locked; + account->name = name; + account->I = I; + account->LastIp = lastip; +} + +void AcctContainer::AddCharacter(RealmCharacter* rcharacter, uint32 realmId, uint32 acctId, uint8 numChars) +{ + rcharacter->realmId = realmId; + rcharacter->acctId = acctId; + rcharacter->numChars = numChars; +} + +void AcctContainer::LoadAll(bool reloading) +{ + // Load accounts + QueryResult* result = dbRealmServer.PQuery("SELECT * FROM `account`"); + + uint32 count = 0; + + if(!result) + return; + + sLog.outString(); + + if(!reloading) + sLog.outString("Loading Accounts In Progress..."); + else + sLog.outString("Reloading Accounts In Progress..."); + + barGoLink bar( result->GetRowCount()); + + // Periodic Database Update ... + dbRealmServer.Execute("UPDATE `account_banned` SET `active` = 0 WHERE `unbandate`<=UNIX_TIMESTAMP() AND `unbandate`<>`bandate`"); + dbRealmServer.Execute("DELETE FROM `ip_banned` WHERE `unbandate`<=UNIX_TIMESTAMP() AND `unbandate`<>`bandate`"); + + Account *acct; + + do + { + Field *fields = result->Fetch(); + bool banned = false; + + bar.step(); + + QueryResult* banresult = dbRealmServer.PQuery("SELECT `bandate`,`unbandate` FROM `account_banned` WHERE `id` = %u AND `active` = 1", fields[0].GetUInt32()); + + if(banresult) + { + banned = true; + delete banresult; + } + + // Create the account + acct = new Account(); + + AddAccount(acct, fields[0].GetUInt32(), fields[4].GetUInt8(), fields[17].GetUInt8(), fields[15].GetUInt8(), banned, fields[12].GetUInt8(), fields[1].GetCppString(), fields[2].GetCppString(), fields[10].GetCppString()); + + m_accounts[acct->id] = acct; + + count++; + + }while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u accounts", count); + + delete result; + + // Now load Ban by ip + + result = dbRealmServer.PQuery("SELECT * FROM `ip_banned`"); + + BanIp* ban; + + // If there is no ban don't load + if(result) + { + sLog.outString(); + + count = 0; + + if(!reloading) + sLog.outString("Loading Ban Ip In Progress..."); + else + sLog.outString("Reloading Ban Ip In Progress..."); + + barGoLink bar( result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + bar.step(); + ban = new BanIp(); + AddBan(ban, fields[0].GetCppString()); + m_banips[ban->Ip] = ban; + count++; + + }while (result->NextRow()); + + delete result; + sLog.outString(); + + sLog.outString(">> Loaded %u ip banned", count); + + count = 0; + } + + // Now load Realm Characters + + result = dbRealmServer.PQuery("SELECT * FROM `realmcharacters`"); + + RealmCharacter *realmcharacter; + + // If there is no ban don't load + if(result) + { + sLog.outString(); + + count = 0; + + if(!reloading) + sLog.outString("Loading Realm Characters In Progress..."); + else + sLog.outString("Reloading Realm Characters In Progress..."); + + barGoLink bar( result->GetRowCount()); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + + realmcharacter = new RealmCharacter(); + + AddCharacter(realmcharacter, fields[0].GetUInt32(), fields[1].GetUInt32(), fields[2].GetUInt8()); + + // Since nothing on this table is unique, order it by increment count value + m_characters[count] = realmcharacter; + + count++; + + }while (result->NextRow()); + + delete result; + + sLog.outString(); + + sLog.outString(">> Loaded %u realm characters", count); + } + + +} + +Account* AcctContainer::FindAccountById(uint32 acctid) +{ + AccountList::const_iterator itr = m_accounts.find(acctid); + + if(itr != m_accounts.end()) + return itr->second; +} + +Account* AcctContainer::FindAccountByName(std::string name) +{ + for(AccountList::const_iterator itr = m_accounts.begin(); itr != m_accounts.end(); itr++) + { + if(!stricmp(itr->second->name.c_str(), name.c_str())) + return itr->second; + } + + return NULL; +} + +bool AcctContainer::IpBan(std::string ClientIp) +{ + for(IpBanList::const_iterator itr = m_banips.begin(); itr != m_banips.end(); itr++) + { + if(!stricmp(itr->second->Ip.c_str(), ClientIp.c_str())) + return true; + } + + return false; +} + +uint8 AcctContainer::GetNumChar(uint32 realmId, uint32 accountId) +{ + for(CharactersList::const_iterator itr = m_characters.begin(); itr != m_characters.end(); itr++) + { + if(itr->second->realmId == realmId && itr->second->acctId == accountId) + return itr->second->numChars; + } + + return 0; +}