void RealmList::UpdateRealm( uint32 ID, const std::string& name, const std::string& address, uint32 port, uint8 icon, RealmFlags realmflags, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, const char* builds) { // Create new if not exist or update existed Realm& realm = m_realms[name]; realm.m_ID = ID; realm.icon = icon; realm.realmflags = realmflags; realm.timezone = timezone; realm.allowedSecurityLevel = allowedSecurityLevel; realm.populationLevel = popu; Tokens tokens = StrSplit(builds, " "); Tokens::iterator iter; for (iter = tokens.begin(); iter != tokens.end(); ++iter) { uint32 build = atol((*iter).c_str()); realm.realmbuilds.insert(build); } uint16 first_build = !realm.realmbuilds.empty() ? *realm.realmbuilds.begin() : 0; realm.realmBuildInfo.build = first_build; realm.realmBuildInfo.major_version = 0; realm.realmBuildInfo.minor_version = 0; realm.realmBuildInfo.bugfix_version = 0; realm.realmBuildInfo.hotfix_version = ' '; if (first_build) if (RealmBuildInfo const* bInfo = FindBuildInfo(first_build)) if (bInfo->build == first_build) realm.realmBuildInfo = *bInfo; // Append port to IP address. std::ostringstream ss; ss << address << ":" << port; realm.address = ss.str(); }
void AuthSocket::LoadRealmlist(ByteBuffer& pkt, uint32 acctid) { switch (_build) { case 5875: // 1.12.1 case 6005: // 1.12.2 case 6141: // 1.12.3 { pkt << uint32(0); // unused value pkt << uint8(sRealmList.size()); for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. QueryResult* result = LoginDatabase.PQuery("SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'", i->second.m_ID, acctid); if (result) { Field* fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); delete result; } else AmountOfCharacters = 0; bool ok_build = std::find(i->second.realmbuilds.begin(), i->second.realmbuilds.end(), _build) != i->second.realmbuilds.end(); RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; if (!buildInfo) buildInfo = &i->second.realmBuildInfo; RealmFlags realmflags = i->second.realmflags; // 1.x clients not support explicitly REALM_FLAG_SPECIFYBUILD, so manually form similar name as show in more recent clients std::string name = i->first; if (realmflags & REALM_FLAG_SPECIFYBUILD) { char buf[20]; snprintf(buf, 20, " (%u,%u,%u)", buildInfo->major_version, buildInfo->minor_version, buildInfo->bugfix_version); name += buf; } // Show offline state for unsupported client builds and locked realms (1.x clients not support locked state show) if (!ok_build || (i->second.allowedSecurityLevel > _accountSecurityLevel)) realmflags = RealmFlags(realmflags | REALM_FLAG_OFFLINE); pkt << uint32(i->second.icon); // realm type pkt << uint8(realmflags); // realmflags pkt << name; // name pkt << i->second.address; // address pkt << float(i->second.populationLevel); pkt << uint8(AmountOfCharacters); pkt << uint8(i->second.timezone); // realm category pkt << uint8(0x00); // unk, may be realm number/id? } pkt << uint16(0x0002); // unused value (why 2?) break; } case 8606: // 2.4.3 case 10505: // 3.2.2a case 11159: // 3.3.0a case 11403: // 3.3.2 case 11723: // 3.3.3a case 12340: // 3.3.5a case 13623: // 4.0.6a case 15050: // 4.3.0 case 15595: // 4.3.4 case 16357: // 5.1.0 case 16992: // 5.3.0 case 17055: // 5.3.0 case 17116: // 5.3.0 case 17128: // 5.3.0 case 17538: // 5.4.1 default: // and later { pkt << uint32(0); // unused value pkt << uint16(sRealmList.size()); for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. QueryResult* result = LoginDatabase.PQuery("SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'", i->second.m_ID, acctid); if (result) { Field* fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); delete result; } else AmountOfCharacters = 0; bool ok_build = std::find(i->second.realmbuilds.begin(), i->second.realmbuilds.end(), _build) != i->second.realmbuilds.end(); RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; if (!buildInfo) buildInfo = &i->second.realmBuildInfo; uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; RealmFlags realmFlags = i->second.realmflags; // Show offline state for unsupported client builds if (!ok_build) realmFlags = RealmFlags(realmFlags | REALM_FLAG_OFFLINE); if (!buildInfo) realmFlags = RealmFlags(realmFlags & ~REALM_FLAG_SPECIFYBUILD); pkt << uint8(i->second.icon); // realm type (this is second column in Cfg_Configs.dbc) pkt << uint8(lock); // flags, if 0x01, then realm locked pkt << uint8(realmFlags); // see enum RealmFlags pkt << i->first; // name pkt << i->second.address; // address pkt << float(i->second.populationLevel); pkt << uint8(AmountOfCharacters); pkt << uint8(i->second.timezone); // realm category (Cfg_Categories.dbc) pkt << uint8(0x2C); // unk, may be realm number/id? if (realmFlags & REALM_FLAG_SPECIFYBUILD) { pkt << uint8(buildInfo->major_version); pkt << uint8(buildInfo->minor_version); pkt << uint8(buildInfo->bugfix_version); pkt << uint16(_build); } } pkt << uint16(0x0010); // unused value (why 10?) break; } } }
/// Logon Proof command handler bool AuthSocket::_HandleLogonProof() { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet sAuthLogonProof_C lp; if (!recv((char*)&lp, sizeof(sAuthLogonProof_C))) return false; ///- Check if the client has one of the expected version numbers bool valid_version = FindBuildInfo(_build) != NULL; /// <ul><li> If the client has no valid version if (!valid_version) { if (this->patch_ != ACE_INVALID_HANDLE) return false; ///- Check if we have the apropriate patch on the disk // file looks like: 65535enGB.mpq char tmp[64]; snprintf(tmp, 24, "./patches/%d%s.mpq", _build, _localizationName.c_str()); char filename[PATH_MAX]; if (ACE_OS::realpath(tmp, filename) != NULL) { patch_ = ACE_OS::open(filename, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN); } if (patch_ == ACE_INVALID_HANDLE) { // no patch found ByteBuffer pkt; pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; pkt << (uint8) WOW_FAIL_VERSION_INVALID; DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); send((char const*)pkt.contents(), pkt.size()); return true; } XFER_INIT xferh; ACE_OFF_T file_size = ACE_OS::filesize(this->patch_); if (file_size == -1) { close_connection(); return false; } if (!PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5)) { // calculate patch md5, happens if patch was added while realmd was running PatchCache::instance()->LoadPatchMD5(tmp); PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5); } uint8 data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE}; send((const char*)data, sizeof(data)); memcpy(&xferh, "0\x05Patch", 7); xferh.cmd = CMD_XFER_INITIATE; xferh.file_size = file_size; send((const char*)&xferh, sizeof(xferh)); return true; } /// </ul> ///- Continue the SRP6 calculation based on data received from the client BigNumber A; A.SetBinary(lp.A, 32); // SRP safeguard: abort if A==0 if (A.isZero()) return false; Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), 20); BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); uint8 t[32]; uint8 t1[16]; uint8 vK[40]; memcpy(t, S.AsByteArray(32), 32); for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2] = sha.GetDigest()[i]; } for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2 + 1]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2 + 1] = sha.GetDigest()[i]; } K.SetBinary(vK, 40); uint8 hash[20]; sha.Initialize(); sha.UpdateBigNumbers(&N, NULL); sha.Finalize(); memcpy(hash, sha.GetDigest(), 20); sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); for (int i = 0; i < 20; ++i) { hash[i] ^= sha.GetDigest()[i]; } BigNumber t3; t3.SetBinary(hash, 20); sha.Initialize(); sha.UpdateData(_login); sha.Finalize(); uint8 t4[SHA_DIGEST_LENGTH]; memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); sha.Initialize(); sha.UpdateBigNumbers(&t3, NULL); sha.UpdateData(t4, SHA_DIGEST_LENGTH); sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); BigNumber M; M.SetBinary(sha.GetDigest(), 20); ///- Check if SRP6 results match (password is correct), else send an error if (!memcmp(M.AsByteArray(), lp.M1, 20)) { BASIC_LOG("User '%s' successfully authenticated", _login.c_str()); ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket const char* K_hex = K.AsHexStr(); LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, get_remote_address().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str()); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); sha.Finalize(); SendProof(sha); ///- Set _authed to true! _authed = true; } else { if (_build > 6005) // > 1.12.2 { char data[4] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; send(data, sizeof(data)); } else { // 1.x not react incorrectly at 4-byte message use 3 as real error char data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT}; send(data, sizeof(data)); } BASIC_LOG("[AuthChallenge] account %s tried to login with wrong password!", _login.c_str()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); if (MaxWrongPassCount > 0) { // Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'", _safelogin.c_str()); if (QueryResult* loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str())) { Field* fields = loginfail->Fetch(); uint32 failed_logins = fields[1].GetUInt32(); if (failed_logins >= MaxWrongPassCount) { uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600); bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false); if (WrongPassBanType) { uint32 acc_id = fields[0].GetUInt32(); LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); } else { std::string current_ip = get_remote_address(); LoginDatabase.escape_string(current_ip); LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); } } delete loginfail; } } } return true; }
/// Logon Proof command handler bool AuthSocket::_HandleLogonProof() { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet if (ibuf.GetLength() < sizeof(sAuthLogonProof_C)) return false; sAuthLogonProof_C lp; ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C)); ///- Check if the client has one of the expected version numbers bool valid_version = FindBuildInfo(_build) != NULL; /// <ul><li> If the client has no valid version /// Ignore if its trial client account if(!valid_version && !_isTrial) { ///- Check if we have the apropriate patch on the disk // 24 = len("./patches/65535enGB.mpq")+1 char tmp[24]; // No buffer overflow (fixed length of arguments) sprintf(tmp, "./patches/%d%s.mpq", _build, _localizationName.c_str()); // This will be closed at the destruction of the AuthSocket (client disconnection) FILE *pFile = fopen(tmp, "rb"); if(!pFile) { ByteBuffer pkt; pkt << (uint8) AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; pkt << (uint8) WOW_FAIL_VERSION_INVALID; DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); SendBuf((char const*)pkt.contents(), pkt.size()); return true; } else // have patch { pPatch = pFile; XFER_INIT xferh; ///- Get the MD5 hash of the patch file (get it from preloaded Patcher cache or calculate it) if(PatchesCache.GetHash(tmp, (uint8*)&xferh.md5)) { DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s", tmp); } else { // calculate patch md5 printf("\n[AuthChallenge] Patch info for %s was not cached.", tmp); PatchesCache.LoadPatchMD5(tmp); PatchesCache.GetHash(tmp, (uint8*)&xferh.md5); } ///- Send a packet to the client with the file length and MD5 hash uint8 data[2] = { AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE }; SendBuf((const char*)data, sizeof(data)); memcpy(&xferh, "0\x05Patch", 7); xferh.cmd = XFER_INITIATE; fseek(pPatch, 0, SEEK_END); xferh.file_size = ftell(pPatch); SendBuf((const char*)&xferh, sizeof(xferh)); return true; } } /// </ul> ///- Continue the SRP6 calculation based on data received from the client BigNumber A; A.SetBinary(lp.A, 32); // SRP safeguard: abort if A==0 if (A.isZero()) return false; Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), 20); BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); uint8 t[32]; uint8 t1[16]; uint8 vK[40]; memcpy(t, S.AsByteArray(32), 32); for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2] = sha.GetDigest()[i]; } for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2 + 1]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2 + 1] = sha.GetDigest()[i]; } K.SetBinary(vK, 40); uint8 hash[20]; sha.Initialize(); sha.UpdateBigNumbers(&N, NULL); sha.Finalize(); memcpy(hash, sha.GetDigest(), 20); sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); for (int i = 0; i < 20; ++i) { hash[i] ^= sha.GetDigest()[i]; } BigNumber t3; t3.SetBinary(hash, 20); sha.Initialize(); sha.UpdateData(_login); sha.Finalize(); uint8 t4[SHA_DIGEST_LENGTH]; memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); sha.Initialize(); sha.UpdateBigNumbers(&t3, NULL); sha.UpdateData(t4, SHA_DIGEST_LENGTH); sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); BigNumber M; M.SetBinary(sha.GetDigest(), 20); ///- Check if SRP6 results match (password is correct), else send an error if (!memcmp(M.AsByteArray(), lp.M1, 20)) { BASIC_LOG("User '%s' successfully authenticated", _login.c_str()); ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket const char* K_hex = K.AsHexStr(); loginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, GetRemoteAddress().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str() ); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); sha.Finalize(); SendProof(sha); ///- Set _authed to true! _authed = true; } else { char data[4]= { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; SendBuf(data, sizeof(data)); BASIC_LOG("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); if(MaxWrongPassCount > 0) { //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP loginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'",_safelogin.c_str()); if(QueryResult *loginfail = loginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str())) { Field* fields = loginfail->Fetch(); uint32 failed_logins = fields[1].GetUInt32(); if( failed_logins >= MaxWrongPassCount ) { uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600); bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false); if(WrongPassBanType) { uint32 acc_id = fields[0].GetUInt32(); loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); } else { std::string current_ip = GetRemoteAddress(); loginDatabase.escape_string(current_ip); loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); } } delete loginfail; } } } return true; }
void AuthSocket::LoadRealmlist(ByteBuffer &pkt, uint32 acctid) { switch(_build) { case 12319: // We support only 4.0.0.12319 { pkt << uint32(0); pkt << uint16(sRealmList.size()); for(RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. QueryResult *result = loginDatabase.PQuery( "SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'", i->second.m_ID, acctid); if( result ) { Field *fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); delete result; } else AmountOfCharacters = 0; bool ok_build = std::find(i->second.realmbuilds.begin(), i->second.realmbuilds.end(), _build) != i->second.realmbuilds.end(); RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; if (!buildInfo) buildInfo = &i->second.realmBuildInfo; uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; RealmFlags realmFlags = i->second.realmflags; // Show offline state for unsupported client builds if (!ok_build) realmFlags = RealmFlags(realmFlags | REALM_FLAG_OFFLINE); if (!buildInfo) realmFlags = RealmFlags(realmFlags & ~REALM_FLAG_SPECIFYBUILD); pkt << uint8(i->second.icon); // realm type (this is second column in Cfg_Configs.dbc) pkt << uint8(lock); // flags, if 0x01, then realm locked pkt << uint8(realmFlags); // see enum RealmFlags pkt << i->first; // name pkt << i->second.address; // address pkt << float(i->second.populationLevel); pkt << uint8(AmountOfCharacters); pkt << uint8(i->second.timezone); // realm category (Cfg_Categories.dbc) pkt << uint8(0x2C); // unk, may be realm number/id? if (realmFlags & REALM_FLAG_SPECIFYBUILD) { pkt << uint8(buildInfo->major_version); pkt << uint8(buildInfo->minor_version); pkt << uint8(buildInfo->bugfix_version); pkt << uint16(_build); } } pkt << uint16(0x0010); break; } } }
void AuthSocket::LoadRealmlist(ByteBuffer& pkt, uint32 acctid) { RealmList::RealmListIterators iters; iters = sRealmList.GetIteratorsForBuild(_build); uint32 numRealms = sRealmList.NumRealmsForBuild(_build); ACE_INET_Addr clientAddr; peer().get_remote_addr(clientAddr); switch (_build) { case 5875: // 1.12.1 case 6005: // 1.12.2 case 6141: // 1.12.3 { pkt << uint32(0); // unused value pkt << uint8(numRealms); for (RealmList::RealmStlList::const_iterator itr = iters.first; itr != iters.second; ++itr) { clientAddr.set_port_number((*itr)->ExternalAddress.get_port_number()); uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. QueryResult* result = LoginDatabase.PQuery("SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'", (*itr)->m_ID, acctid); if (result) { Field* fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); delete result; } else AmountOfCharacters = 0; bool ok_build = std::find((*itr)->realmbuilds.begin(), (*itr)->realmbuilds.end(), _build) != (*itr)->realmbuilds.end(); RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; if (!buildInfo) buildInfo = &(*itr)->realmBuildInfo; RealmFlags realmflags = (*itr)->realmflags; // 1.x clients not support explicitly REALM_FLAG_SPECIFYBUILD, so manually form similar name as show in more recent clients std::string name = (*itr)->name; if (realmflags & REALM_FLAG_SPECIFYBUILD) { char buf[20]; snprintf(buf, 20, " (%u,%u,%u)", buildInfo->major_version, buildInfo->minor_version, buildInfo->bugfix_version); name += buf; } // Show offline state for unsupported client builds and locked realms (1.x clients not support locked state show) if (!ok_build || ((*itr)->allowedSecurityLevel > _accountSecurityLevel)) realmflags = RealmFlags(realmflags | REALM_FLAG_OFFLINE); pkt << uint32((*itr)->icon); // realm type pkt << uint8(realmflags); // realmflags pkt << name; // name pkt << GetAddressString(GetAddressForClient((**itr), clientAddr)); // address pkt << float((*itr)->populationLevel); pkt << uint8(AmountOfCharacters); pkt << uint8((*itr)->timezone); // realm category pkt << uint8(0x00); // unk, may be realm number/id? } pkt << uint16(0x0002); // unused value (why 2?) break; } case 8606: // 2.4.3 case 10505: // 3.2.2a case 11159: // 3.3.0a case 11403: // 3.3.2 case 11723: // 3.3.3a case 12340: // 3.3.5a case 13623: // 4.0.6a case 15050: // 4.3.0 case 15595: // 4.3.4 case 16357: // 5.1.0 case 16992: // 5.3.0 case 17055: // 5.3.0 case 17116: // 5.3.0 case 17128: // 5.3.0 case 17538: // 5.4.1 case 17658: // 5.4.2 case 17688: // 5.4.2a case 17898: // 5.4.7 case 17930: // 5.4.7 case 17956: // 5.4.7 case 18019: // 5.4.7 case 18291: // 5.4.8 case 18414: // 5.4.8 default: // and later { pkt << uint32(0); // unused value pkt << uint16(numRealms); for (RealmList::RealmStlList::const_iterator itr = iters.first; itr != iters.second; ++itr) { clientAddr.set_port_number((*itr)->ExternalAddress.get_port_number()); uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. QueryResult* result = LoginDatabase.PQuery("SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'", (*itr)->m_ID, acctid); if (result) { Field* fields = result->Fetch(); AmountOfCharacters = fields[0].GetUInt8(); delete result; } else { AmountOfCharacters = 0; } bool ok_build = std::find((*itr)->realmbuilds.begin(), (*itr)->realmbuilds.end(), _build) != (*itr)->realmbuilds.end(); RealmBuildInfo const* buildInfo = ok_build ? FindBuildInfo(_build) : NULL; if (!buildInfo) { buildInfo = &(*itr)->realmBuildInfo; } uint8 lock = ((*itr)->allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; RealmFlags realmFlags = (*itr)->realmflags; // Show offline state for unsupported client builds if (!ok_build) { realmFlags = RealmFlags(realmFlags | REALM_FLAG_OFFLINE); } if (!buildInfo) { realmFlags = RealmFlags(realmFlags & ~REALM_FLAG_SPECIFYBUILD); } pkt << uint8((*itr)->icon); // realm type (this is second column in Cfg_Configs.dbc) pkt << uint8(lock); // flags, if 0x01, then realm locked pkt << uint8(realmFlags); // see enum RealmFlags pkt << (*itr)->name; // name pkt << GetAddressString(GetAddressForClient((**itr), clientAddr)); // address pkt << float((*itr)->populationLevel); pkt << uint8(AmountOfCharacters); pkt << uint8((*itr)->timezone); // realm category (Cfg_Categories.dbc) pkt << uint8(0x2C); // unk, may be realm number/id? if (realmFlags & REALM_FLAG_SPECIFYBUILD) { pkt << uint8(buildInfo->major_version); pkt << uint8(buildInfo->minor_version); pkt << uint8(buildInfo->bugfix_version); pkt << uint16(_build); } } pkt << uint16(0x0010); // unused value (why 10?) break; } } }