void ClusterInterface::ConnectToRealmServer() { _lastConnectTime = UNIXTIME; string hostname; int port; string strkey; if(!Config.MainConfig.GetString("Cluster", "RSHostName", &hostname) || !Config.MainConfig.GetInt("Cluster", "RSPort", &port) || !Config.MainConfig.GetString("Cluster", "Key", &strkey)) { Log.Error("ClusterInterface", "Could not get necessary fields from config file. Please fix and rehash."); return; } /* hash the key */ Sha1Hash k; k.UpdateData(strkey); k.Finalize(); memcpy(key, k.GetDigest(), 20); Log.Notice("ClusterInterface", "Connecting to %s port %u", hostname.c_str(), port); WSClient * s = ConnectTCPSocket<WSClient>(hostname.c_str(), port); if(!s) { Log.Error("ClusterInterface", "Could not connect to %s:%u", hostname.c_str(), port); return; } Log.Success("ClusterInterface", "Connected to %s:%u", hostname.c_str(), port); _clientSocket = s; m_latency = getMSTime(); m_connected = true; }
LogonCommHandler::LogonCommHandler() { idhigh = 1; next_request = 1; pings = !Config.MainConfig.GetBoolDefault("LogonServer", "DisablePings", false); string logon_pass = Config.MainConfig.GetStringDefault("LogonServer", "RemotePassword", "r3m0t3"); // sha1 hash it Sha1Hash hash; hash.UpdateData(logon_pass); hash.Finalize(); memset(sql_passhash, 0, 20); memcpy(sql_passhash, hash.GetDigest(), 20); // player limit pLimit = Config.MainConfig.GetIntDefault("Server", "PlayerLimit", 500); if (pLimit == 0) pLimit = 1; server_population = 0; _realmType = 0; // cleanup servers.clear(); realms.clear(); }
void AccountMgr::UpdateAccount(Account * acct, Field * field) { uint32 id = field[0].GetUInt32(); if(id != acct->AccountId) { //printf("Account %u `%s` is a duplicate.\n", id, acct->Username.c_str()); sLog.outColor(TYELLOW, " >> deleting duplicate account %u [%s]...", id, acct->Username.c_str()); sLog.outColor(TNORMAL, "\n"); sLogonSQL->Execute("DELETE FROM accounts WHERE acct=%u", id); return; } acct->AccountId = field[0].GetUInt32(); acct->Username = field[1].GetString(); acct->Password = field[2].GetString(); acct->GMFlags = field[3].GetString(); acct->AccountFlags = field[4].GetUInt32(); acct->Banned = field[5].GetUInt32(); // Convert username/password to uppercase. this is needed ;) transform(acct->Username.begin(), acct->Username.end(), acct->Username.begin(), towupper); transform(acct->Password.begin(), acct->Password.end(), acct->Password.begin(), towupper); Sha1Hash hash; hash.UpdateData((acct->Username + ":" + acct->Password)); hash.Finalize(); memcpy(acct->SrpHash, hash.GetDigest(), 20); }
void LogonCommHandler::TestConsoleLogon(string& username, string& password, uint32 requestnum) { string newuser = username; string newpass = password; string srpstr; arcemu_TOUPPER(newuser); arcemu_TOUPPER(newpass); srpstr = newuser + ":" + newpass; // Send request packet to server. map<LogonServer*, LogonCommClientSocket*>::iterator itr = logons.begin(); if(logons.size() == 0 || itr->second == 0) { // No valid logonserver is connected. return; } Sha1Hash hash; hash.UpdateData(srpstr); hash.Finalize(); WorldPacket data(RCMSG_TEST_CONSOLE_LOGIN, 100); data << requestnum; data << newuser; data.append(hash.GetDigest(), 20); itr->second->SendPacket(&data, false); }
/// Make the SRP6 calculation from hash in dB void AuthSocket::_SetVSFields(const std::string& rI) { s.SetRand(s_BYTE_SIZE * 8); BigNumber I; I.SetHexStr(rI.c_str()); // In case of leading zeros in the rI hash, restore them uint8 mDigest[SHA_DIGEST_LENGTH]; memset(mDigest, 0, SHA_DIGEST_LENGTH); if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) memcpy(mDigest, I.AsByteArray(), I.GetNumBytes()); std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); Sha1Hash sha; sha.UpdateData(s.AsByteArray(), s.GetNumBytes()); sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); sha.Finalize(); BigNumber x; x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); // No SQL injection (username escaped) const char* v_hex, *s_hex; v_hex = v.AsHexStr(); s_hex = s.AsHexStr(); LoginDatabase.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '******'", v_hex, s_hex, _safelogin.c_str()); OPENSSL_free((void*)v_hex); OPENSSL_free((void*)s_hex); }
void AuthSocket::HandleReconnectProof() { if( m_account == NULL ) return; // Load sessionkey from account database. QueryResult * result = sLogonSQL->Query ("SELECT SessionKey FROM accounts WHERE acct = %u", m_account->AccountId); if(result) { Field * field = result->Fetch(); K.SetHexStr(field[0].GetString ()); delete result; } else { // Disconnect if the sessionkey invalid or not found DEBUG_LOG("AuthReConnectProof","No matching SessionKey found while user %s tried to login.", AccountName.c_str()); Disconnect(); return; } if(GetReadBuffer().GetSize() < sizeof(sAuthLogonProofKey_C)) return; sAuthLogonProofKey_C lp; GetReadBuffer().Read(&lp, sizeof(sAuthLogonProofKey_C)); BigNumber A; A.SetBinary(lp.R1, 16); Sha1Hash sha; sha.Initialize(); sha.UpdateData(AccountName); sha.UpdateBigNumbers(&A, &rs, &K, 0); sha.Finalize(); if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) { ///- Sending response ByteBuffer pkt; pkt << (uint8) 0x03; //ReconnectProof pkt << (uint8) 0x00; pkt << (uint16) 0x00; // 2 bytes zeros Send(pkt.contents(), pkt.size()); // we're authenticated now :) m_authenticated = true; DEBUG_LOG("AuthReConnectProof","Authentication Success."); } else DEBUG_LOG("AuthReConnectProof","Authentication Failed."); }
LogonCommHandler::LogonCommHandler() { idhigh = 1; next_request = 1; pings = !Config.MainConfig.GetBoolDefault("LogonServer", "DisablePings", false); string logon_pass = Config.MainConfig.GetStringDefault("LogonServer", "RemotePassword", "r3m0t3"); // sha1 hash it Sha1Hash hash; hash.UpdateData(logon_pass); hash.Finalize(); memcpy(sql_passhash, hash.GetDigest(), 20); }
std::string AccountMgr::CalculateShaPassHash(std::string& name, std::string& password) { Sha1Hash sha; sha.Initialize(); sha.UpdateData(name); sha.UpdateData(":"); sha.UpdateData(password); sha.Finalize(); std::string encoded; hexEncodeByteArray(sha.GetDigest(), sha.GetLength(), encoded); return encoded; }
/// Reconnect Proof command handler bool AuthSocket::_HandleReconnectProof() { DEBUG_LOG("Entering _HandleReconnectProof"); ///- Read the packet sAuthReconnectProof_C lp; if (!recv((char*)&lp, sizeof(sAuthReconnectProof_C))) { return false; } if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) { return false; } BigNumber t1; t1.SetBinary(lp.R1, 16); Sha1Hash sha; sha.Initialize(); sha.UpdateData(_login); sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); sha.Finalize(); if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) { ///- Sending response ByteBuffer pkt; pkt << (uint8) CMD_AUTH_RECONNECT_PROOF; pkt << (uint8) 0x00; //If we keep from sending this we don't receive Session Expired on the client when //changing realms after being logged on to the world if (_build > 6141) // Last vanilla, 1.12.3 pkt << (uint16) 0x00; // 2 bytes zeros send((char const*)pkt.contents(), pkt.size()); ///- Set _authed to true! _authed = true; return true; } else { sLog.outError("[ERROR] user %s tried to login, but session invalid.", _login.c_str()); close_connection(); return false; } }
void AccountMgr::AddAccount() { Account* acct = new Account; Sha1Hash hash; string Username = "******"; string Password = "******"; acct->AccountId = 1; acct->AccountFlags = 1; acct->Banned = 1; if((uint32)UNIXTIME > acct->Banned && acct->Banned != 0 && acct->Banned != 1) //1 = perm ban? { //Accounts should be unbanned once the date is past their set expiry date. acct->Banned = 0; //me go boom :( //printf("Account %s's ban has expired.\n",acct->UsernamePtr->c_str()); //sLogonSQL->Execute("UPDATE accounts SET banned = 0 WHERE acct=%u", acct->AccountId); } acct->SetGMFlags("test"); acct->Locale[0] = 'e'; acct->Locale[1] = 'n'; acct->Locale[2] = 'U'; acct->Locale[3] = 'S'; acct->forcedLocale = false; acct->Muted = 1; if((uint32)UNIXTIME > acct->Muted && acct->Muted != 0 && acct->Muted != 1) //1 = perm ban? { //Accounts should be unbanned once the date is past their set expiry date. acct->Muted = 0; //LOG_DEBUG("Account %s's mute has expired.",acct->UsernamePtr->c_str()); //sLogonSQL->Execute("UPDATE accounts SET muted = 0 WHERE acct=%u", acct->AccountId); } // Convert username/password to uppercase. this is needed ;) mnet_TOUPPER(Username); mnet_TOUPPER(Password); // prefer encrypted passwords over nonencrypted // Prehash the I value. hash.UpdateData((Username + ":" + Password)); hash.Finalize(); memcpy(acct->SrpHash, hash.GetDigest(), 20); AccountDatabase[Username] = acct; }
/// Reconnect Proof command handler bool AuthSocket::_HandleReconnectProof() { DEBUG_LOG("Entering _HandleReconnectProof"); ///- Read the packet if (ibuf.GetLength() < sizeof(sAuthReconnectProof_C)) return false; if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; sAuthReconnectProof_C lp; ibuf.Read((char *)&lp, sizeof(sAuthReconnectProof_C)); BigNumber t1; t1.SetBinary(lp.R1, 16); Sha1Hash sha; sha.Initialize(); sha.UpdateData(_login); sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); sha.Finalize(); if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) { ///- Sending response ByteBuffer pkt; pkt << (uint8) AUTH_RECONNECT_PROOF; pkt << (uint8) 0x00; pkt << (uint16) 0x00; // 2 bytes zeros SendBuf((char const*)pkt.contents(), pkt.size()); ///- Set _authed to true! _authed = true; return true; } else { sLog.outError("[ERROR] user %s tried to login, but session invalid.", _login.c_str()); SetCloseAndDelete(); return false; } }
/// Reconnect Proof command handler bool AuthSocket::_HandleReconnectProof() { DEBUG_LOG("Entering _HandleReconnectProof"); ///- Read the packet sAuthReconnectProof_C lp; if(!recv((char *)&lp, sizeof(sAuthReconnectProof_C))) return false; if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; BigNumber t1; t1.SetBinary(lp.R1, 16); Sha1Hash sha; sha.Initialize(); sha.UpdateData(_login); sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); sha.Finalize(); if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) { ///- Sending response ByteBuffer pkt; pkt << uint8(CMD_AUTH_RECONNECT_PROOF); pkt << uint8(0x00); pkt << uint16(0x00); // 2 bytes zeros send((char const*)pkt.contents(), pkt.size()); ///- Set _authed to true! _authed = true; return true; } else { sLog.outLog(LOG_DEFAULT, "ERROR: [ERROR] user %s tried to login, but session invalid.", _login.c_str()); close_connection(); return false; } }
void AccountMgr::AddAccount(Field* field) { Account acct; Sha1Hash hash; acct.AccountId = field[0].GetUInt32(); acct.Username = field[1].GetString(); acct.Password = field[2].GetString(); acct.GMFlags = field[3].GetString(); acct.AccountFlags = field[4].GetUInt32(); acct.Banned = field[5].GetUInt32(); // Convert username/password to uppercase. this is needed ;) transform(acct.Username.begin(), acct.Username.end(), acct.Username.begin(), towupper); transform(acct.Password.begin(), acct.Password.end(), acct.Password.begin(), towupper); // Prehash the I value. hash.UpdateData((acct.Username + ":" + acct.Password)); hash.Finalize(); memcpy(acct.SrpHash, hash.GetDigest(), 20); AccountDatabase[acct.Username] = acct; }
/// Make the SRP6 calculation from hash in dB void AuthSocket::_SetVSFields(std::string rI) { BigNumber I; I.SetHexStr(rI.c_str()); //In case of leading zeroes in the rI hash, restore them uint8 mDigest[SHA_DIGEST_LENGTH]; memset(mDigest,0,SHA_DIGEST_LENGTH); if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) memcpy(mDigest,I.AsByteArray(),I.GetNumBytes()); std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH); Sha1Hash sha; sha.UpdateData(s.AsByteArray(), s.GetNumBytes()); sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); sha.Finalize(); BigNumber x; x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); // No SQL injection (username escaped) dbRealmServer.PExecute("UPDATE `account` SET `v` = '%s', `s` = '%s' WHERE UPPER(`username`)= UPPER('%s')",v.AsHexStr(),s.AsHexStr(), _safelogin.c_str() ); }
void AuthSocket::HandleProof() { if(GetReadBuffer()->GetSize() < sizeof(sAuthLogonProof_C)) return; // patch if(m_patch&&!m_account) { //RemoveReadBufferBytes(75,false); GetReadBuffer()->Remove(75); DEBUG_LOG("AuthLogonProof","Intitiating PatchJob"); uint8 bytes[2] = {0x01,0x0a}; Send(bytes,2); PatchMgr::getSingleton().InitiatePatch(m_patch, this); return; } if(!m_account) return; DEBUG_LOG("AuthLogonProof","Interleaving and checking proof..."); sAuthLogonProof_C lp; GetReadBuffer()->Read(&lp, sizeof(sAuthLogonProof_C)); BigNumber A; A.SetBinary(lp.A, 32); Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, 0); 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); 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]; } m_sessionkey.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((const uint8*)m_account->UsernamePtr->c_str(), (int)m_account->UsernamePtr->size()); sha.Finalize(); BigNumber t4; t4.SetBinary(sha.GetDigest(), 20); sha.Initialize(); sha.UpdateBigNumbers(&t3, &t4, &s, &A, &B, &m_sessionkey, NULL); sha.Finalize(); BigNumber M; M.SetBinary(sha.GetDigest(), 20); // Compare M1 values. if(memcmp(lp.M1, M.AsByteArray(), 20) != 0) { // Authentication failed. //SendProofError(4, 0); SendChallengeError(CE_NO_ACCOUNT); DEBUG_LOG("AuthLogonProof","M1 values don't match."); return; } // Store sessionkey m_account->SetSessionKey(m_sessionkey.AsByteArray()); // OUT_DEBUG("========================\nSession key: "); // for(uint32 z = 0; z < 40; ++z) // OUT_DEBUG("%.2X ", m_account->SessionKey[z]); // OUT_DEBUG("\n========================\n"); // let the client know sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &m_sessionkey, 0); sha.Finalize(); if(GetBuild() <= 6005) { sAuthLogonProof_S proof; proof.cmd = 0x01; proof.error = 0; memcpy(proof.M2, sha.GetDigest(), 20); proof.unk2 = 0; SendPacket( (uint8*) &proof, sizeof(proof) ); } else SendProofError(0, sha.GetDigest()); DEBUG_LOG("AuthLogonProof","Authentication Success."); // we're authenticated now :) m_authenticated = true; // Don't update when IP banned, but update anyway if it's an account ban const char* m_sessionkey_hex = m_sessionkey.AsHexStr(); sLogonSQL->Execute("UPDATE accounts SET lastlogin=NOW(), SessionKey = '%s', lastip='%s' WHERE acct=%u;", m_sessionkey_hex, GetIP(), m_account->AccountId); }
/// 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::HandleChallenge() { // No header if(readBuffer.GetContiguiousBytes() < 4) { LOG_ERROR("[AuthChallenge] Packet has no header. Refusing to handle."); return; } // Check the rest of the packet is complete. uint8* ReceiveBuffer = (uint8*)readBuffer.GetBufferStart(); uint16 full_size = *(uint16*)&ReceiveBuffer[2]; LOG_DETAIL("[AuthChallenge] got header, body is %u bytes", full_size); if(readBuffer.GetSize() < uint32(full_size + 4)) { LOG_ERROR("[AuthChallenge] Packet is smaller than expected, refusing to handle"); return; } // Copy the data into our cached challenge structure if(full_size > sizeof(sAuthLogonChallenge_C)) { LOG_ERROR("[AuthChallenge] Packet is larger than expected, refusing to handle!"); Disconnect(); return; } LOG_DEBUG("[AuthChallenge] got a complete packet."); //memcpy(&m_challenge, ReceiveBuffer, full_size + 4); //RemoveReadBufferBytes(full_size + 4, true); readBuffer.Read(&m_challenge, full_size + 4); // Check client build. uint16 build = m_challenge.build; // Check client build. if(build > LogonServer::getSingleton().max_build) { // wtf? LOG_DETAIL("[AuthChallenge] Client %s has wrong version. More up to date than server. Server: %u, Client: %u", GetRemoteIP().c_str(), LogonServer::getSingleton().max_build, m_challenge.build); SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } if(build < LogonServer::getSingleton().min_build) { // can we patch? char flippedloc[5] = {0, 0, 0, 0, 0}; flippedloc[0] = m_challenge.country[3]; flippedloc[1] = m_challenge.country[2]; flippedloc[2] = m_challenge.country[1]; flippedloc[3] = m_challenge.country[0]; m_patch = PatchMgr::getSingleton().FindPatchForClient(build, flippedloc); if(m_patch == NULL) { // could not find a valid patch LOG_DETAIL("[AuthChallenge] Client %s has wrong version. More out of date than server. Server: %u, Client: %u", GetRemoteIP().c_str(), LogonServer::getSingleton().min_build, m_challenge.build); SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } Log.Debug("Patch", "Selected patch %u%s for client.", m_patch->Version, m_patch->Locality); uint8 response[119] = { 0x00, 0x00, 0x00, 0x72, 0x50, 0xa7, 0xc9, 0x27, 0x4a, 0xfa, 0xb8, 0x77, 0x80, 0x70, 0x22, 0xda, 0xb8, 0x3b, 0x06, 0x50, 0x53, 0x4a, 0x16, 0xe2, 0x65, 0xba, 0xe4, 0x43, 0x6f, 0xe3, 0x29, 0x36, 0x18, 0xe3, 0x45, 0x01, 0x07, 0x20, 0x89, 0x4b, 0x64, 0x5e, 0x89, 0xe1, 0x53, 0x5b, 0xbd, 0xad, 0x5b, 0x8b, 0x29, 0x06, 0x50, 0x53, 0x08, 0x01, 0xb1, 0x8e, 0xbf, 0xbf, 0x5e, 0x8f, 0xab, 0x3c, 0x82, 0x87, 0x2a, 0x3e, 0x9b, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x32, 0xa3, 0x49, 0x76, 0x5c, 0x5b, 0x35, 0x9a, 0x93, 0x3c, 0x6f, 0x3c, 0x63, 0x6d, 0xc0, 0x00 }; Send(response, 119); return; } // Check for a possible IP ban on this client. BAN_STATUS ipb = IPBanner::getSingleton().CalculateBanStatus(GetRemoteAddress()); if(ipb != BAN_STATUS_NOT_BANNED) LOG_DETAIL("[AuthChallenge] Client %s is banned, refusing to continue.", GetRemoteIP().c_str()); switch(ipb) { case BAN_STATUS_PERMANENT_BAN: SendChallengeError(CE_ACCOUNT_CLOSED); return; case BAN_STATUS_TIME_LEFT_ON_BAN: SendChallengeError(CE_ACCOUNT_FREEZED); return; default: break; } // Null-terminate the account string if(m_challenge.I_len >= 50) { Disconnect(); return; } m_challenge.I[m_challenge.I_len] = 0; // Clear the shitty hash (for server) string AccountName = (char*)&m_challenge.I; string::size_type i = AccountName.rfind("#"); if(i != string::npos) { LOG_ERROR("# ACCOUNTNAME!"); return; //AccountName.erase( i ); } // Look up the account information LOG_DEBUG("[AuthChallenge] Account Name: \"%s\"", AccountName.c_str()); m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { LOG_DEBUG("[AuthChallenge] Invalid account."); // Non-existant account SendChallengeError(CE_NO_ACCOUNT); return; } LOG_DEBUG("[AuthChallenge] Account banned state = %u", m_account->Banned); // Check that the account isn't banned. if(m_account->Banned == 1) { SendChallengeError(CE_ACCOUNT_CLOSED); return; } else if(m_account->Banned > 0) { SendChallengeError(CE_ACCOUNT_FREEZED); return; } // update cached locale if(!m_account->forcedLocale) { char temp[4]; temp[0] = m_challenge.country[3]; temp[1] = m_challenge.country[2]; temp[2] = m_challenge.country[1]; temp[3] = m_challenge.country[0]; *(uint32*)&m_account->Locale[0] = *(uint32*)temp; } //////////////////////////////////////////////// SRP6 Challenge //////////////////////////////////////////////// // // // First we will generate the Verifier value using the following formulas // // x = SHA1(s | SHA1(I | ":" | P)) // v = g^x % N // // The SHA1(I | ":" | P) part for x we have in the account database, this is the encrypted password, reversed // N is a safe prime // g is the generator // | means concatenation in this contect // // Sha1Hash sha; sha.UpdateData(s.AsByteArray(), 32); sha.UpdateData(m_account->SrpHash, 20); sha.Finalize(); BigNumber x; x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); // Next we generate b, and B which are the public and private values of the server // // b = random() // B = k*v + g^b % N // // in our case the multiplier parameters, k = 3 b.SetRand(152); uint8 k = 3; BigNumber gmod = g.ModExp(b, N); B = ((v * k) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk; unk.SetRand(128); // Now we send B, g, N and s to the client as a challenge, asking the client for the proof sAuthLogonChallenge_S challenge; challenge.cmd = 0; challenge.error = 0; challenge.unk2 = CE_SUCCESS; memcpy(challenge.B, B.AsByteArray(), 32); challenge.g_len = 1; challenge.g = (g.AsByteArray())[ 0 ]; challenge.N_len = 32; memcpy(challenge.N, N.AsByteArray(), 32); memcpy(challenge.s, s.AsByteArray(), 32); memcpy(challenge.unk3, unk.AsByteArray(), 16); challenge.unk4 = 0; Send(reinterpret_cast< uint8* >(&challenge), sizeof(sAuthLogonChallenge_S)); }
void AuthSocket::HandleProof() { if(readBuffer.GetSize() < sizeof(sAuthLogonProof_C)) { LOG_ERROR("[AuthLogonProof] The packet received is larger than expected, refusing to handle it!"); return ; } // patch if(m_patch && !m_account) { //RemoveReadBufferBytes(75,false); readBuffer.Remove(75); LOG_DEBUG("[AuthLogonProof] Intitiating PatchJob"); uint8 bytes[2] = {0x01, 0x0a}; Send(bytes, 2); PatchMgr::getSingleton().InitiatePatch(m_patch, this); return; } if(!m_account) return; LOG_DEBUG("[AuthLogonProof] Interleaving and checking proof..."); sAuthLogonProof_C lp; //Read(sizeof(sAuthLogonProof_C), (uint8*)&lp); readBuffer.Read(&lp, sizeof(sAuthLogonProof_C)); ////////////////////////////////////////////////////// SRP6 /////////////////////////////////////////////// //Now comes the famous secret Xi Chi fraternity handshake ( http://www.youtube.com/watch?v=jJSYBoI2si0 ), //generating a session key // // A = g^a % N // u = SHA1( A | B ) // // BigNumber A; A.SetBinary(lp.A, 32); Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, 0); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), 20); // S session key key, S = ( A * v^u ) ^ b BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); // Generate M // M = H(H(N) xor H(g), H(I), s, A, B, K) according to http://srp.stanford.edu/design.html uint8 t[32]; uint8 t1[16]; uint8 vK[40]; memcpy(t, S.AsByteArray(), 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]; } m_sessionkey.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((const uint8*)m_account->UsernamePtr->c_str(), (int)m_account->UsernamePtr->size()); sha.Finalize(); BigNumber t4; t4.SetBinary(sha.GetDigest(), 20); sha.Initialize(); sha.UpdateBigNumbers(&t3, &t4, &s, &A, &B, &m_sessionkey, NULL); sha.Finalize(); BigNumber M; M.SetBinary(sha.GetDigest(), 20); // Compare the M value the client sent us to the one we generated, this proves we both have the same values // which proves we have the same username-password pairs if(memcmp(lp.M1, M.AsByteArray(), 20) != 0) { // Authentication failed. //SendProofError(4, 0); SendChallengeError(CE_NO_ACCOUNT); LOG_DEBUG("[AuthLogonProof] M values don't match. ( Either invalid password or the logon server is bugged. )"); return; } // Store sessionkey m_account->SetSessionKey(m_sessionkey.AsByteArray()); // let the client know sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &m_sessionkey, 0); sha.Finalize(); SendProofError(0, sha.GetDigest()); LOG_DEBUG("[AuthLogonProof] Authentication Success."); // we're authenticated now :) m_authenticated = true; // Don't update when IP banned, but update anyway if it's an account ban sLogonSQL->Execute("UPDATE accounts SET lastlogin=NOW(), lastip='%s' WHERE acct=%u;", GetRemoteIP().c_str(), m_account->AccountId); }
bool WorldSocket::HandleAuthSession(WorldPacket &recvPacket) { // NOTE: ATM the socket is singlethread, have this in mind ... uint8 digest[20]; uint32 clientSeed, id, security; uint32 ClientBuild; LocaleConstant locale; std::string account; Sha1Hash sha1; BigNumber v, s, g, N, K; WorldPacket packet, SendAddonPacked; // Read the content of the packet recvPacket >> ClientBuild; recvPacket.read_skip<uint32>(); recvPacket >> account; recvPacket >> clientSeed; recvPacket.read(digest, 20); DEBUG_LOG("WorldSocket::HandleAuthSession: client build %u, account %s, clientseed %X", ClientBuild, account.c_str(), clientSeed); // Check the version of client trying to connect if (!IsAcceptableClientBuild(ClientBuild)) { packet.Initialize(SMSG_AUTH_RESPONSE, 1); packet << uint8(AUTH_VERSION_MISMATCH); SendPacket(packet); sLog.outError("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch)."); return false; } // Get the account information from the realmd database std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below LoginDatabase.escape_string(safe_account); // No SQL injection, username escaped. QueryResult* result = LoginDatabase.PQuery("SELECT " "id, " //0 "gmlevel, " //1 "sessionkey, " //2 "last_ip, " //3 "locked, " //4 "v, " //5 "s, " //6 "mutetime, " //7 "locale " //8 "FROM account " "WHERE username = '******'", safe_account.c_str()); // Stop if the account is not found if (!result) { packet.Initialize(SMSG_AUTH_RESPONSE, 1); packet << uint8(AUTH_UNKNOWN_ACCOUNT); SendPacket(packet); sLog.outError("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); return false; } Field* fields = result->Fetch(); N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); g.SetDword(7); v.SetHexStr(fields[5].GetString()); s.SetHexStr(fields[6].GetString()); m_s = s; const char* sStr = s.AsHexStr(); // Must be freed by OPENSSL_free() const char* vStr = v.AsHexStr(); // Must be freed by OPENSSL_free() DEBUG_LOG("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s", sStr, vStr); OPENSSL_free((void*) sStr); OPENSSL_free((void*) vStr); ///- Re-check ip locking (same check as in realmd). if (fields[4].GetUInt8() == 1) // if ip is locked { if (strcmp(fields[3].GetString(), GetRemoteAddress().c_str())) { packet.Initialize(SMSG_AUTH_RESPONSE, 1); packet << uint8(AUTH_FAILED); SendPacket(packet); delete result; BASIC_LOG("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); return false; } } id = fields[0].GetUInt32(); security = fields[1].GetUInt16(); if (security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB security = SEC_ADMINISTRATOR; K.SetHexStr(fields[2].GetString()); time_t mutetime = time_t (fields[7].GetUInt64()); uint8 tempLoc = LocaleConstant(fields[8].GetUInt8()); if (tempLoc >= static_cast<uint8>(MAX_LOCALE)) locale = LOCALE_enUS; else locale = LocaleConstant(tempLoc); delete result; // Re-check account ban (same check as in realmd) QueryResult* banresult = LoginDatabase.PQuery("SELECT 1 FROM account_banned WHERE id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)" "UNION " "SELECT 1 FROM ip_banned WHERE (unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", id, GetRemoteAddress().c_str()); if (banresult) // if account banned { packet.Initialize(SMSG_AUTH_RESPONSE, 1); packet << uint8(AUTH_BANNED); SendPacket(packet); delete banresult; sLog.outError("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); return false; } // Check locked state for server AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType) { WorldPacket Packet(SMSG_AUTH_RESPONSE, 1); Packet << uint8(AUTH_UNAVAILABLE); SendPacket(packet); BASIC_LOG("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); return false; } // Check that Key and account name are the same on client and server Sha1Hash sha; uint32 t = 0; uint32 seed = m_seed; sha.UpdateData(account); sha.UpdateData((uint8*) & t, 4); sha.UpdateData((uint8*) & clientSeed, 4); sha.UpdateData((uint8*) & seed, 4); sha.UpdateBigNumbers(&K, nullptr); sha.Finalize(); if (memcmp(sha.GetDigest(), digest, 20)) { packet.Initialize(SMSG_AUTH_RESPONSE, 1); packet << uint8(AUTH_FAILED); SendPacket(packet); sLog.outError("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); return false; } const std::string &address = GetRemoteAddress(); DEBUG_LOG("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", account.c_str(), address.c_str()); // Update the last_ip in the database // No SQL injection, username escaped. static SqlStatementID updAccount; SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE account SET last_ip = ? WHERE username = ?"); stmt.PExecute(address.c_str(), account.c_str()); if (!(m_session = new WorldSession(id, this, AccountTypes(security), mutetime, locale))) return false; m_crypt.Init(&K); m_session->LoadTutorialsData(); sWorld.AddSession(m_session); // Create and send the Addon packet if (sAddOnHandler.BuildAddonPacket(recvPacket, SendAddonPacked)) SendPacket(SendAddonPacked); return true; }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); ibuf.Read((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ibuf.GetLength() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ///- Read the remaining of the packet ibuf.Read((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; loginDatabase.escape_string(_safelogin); pkt << (uint8) AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); std::string address = GetRemoteAddress(); loginDatabase.escape_string(address); QueryResult *result = loginDatabase.PQuery("SELECT * FROM ip_banned WHERE ip = '%s'",address.c_str()); if(result) { pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED; sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!",GetRemoteAddress().c_str ()); delete result; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) result = loginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'",_safelogin.c_str ()); if( result ) { ///- If the IP is 'locked', check that the player comes indeed from the correct IP address bool locked = false; if((*result)[2].GetUInt8() == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", GetRemoteAddress().c_str()); if ( strcmp((*result)[3].GetString(),GetRemoteAddress().c_str()) ) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED; locked=true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!locked) { //set expired bans to inactive loginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); ///- If the account is banned, reject the logon attempt QueryResult *banresult = loginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = %u AND active = 1", (*result)[1].GetUInt32()); if(banresult) { if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << (uint8) REALM_AUTH_ACCOUNT_BANNED; sLog.outBasic("[AuthChallenge] Banned account %s tries to login!",_login.c_str ()); } else { pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED; sLog.outBasic("[AuthChallenge] Temporarily banned account %s tries to login!",_login.c_str ()); } delete banresult; } else { ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = (*result)[0].GetCppString(); ///- Don't calculate (v, s) if there are already some in the database std::string databaseV = (*result)[5].GetCppString(); std::string databaseS = (*result)[6].GetCppString(); sLog.outDebug("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2, bytes are stored as hexstring if(databaseV.size() != s_BYTE_SIZE*2 || databaseS.size() != s_BYTE_SIZE*2) _SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); ///- Fill the response packet with the result pkt << uint8(REALM_AUTH_SUCCESS); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if(securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if(securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if(securityFlags & 0x04) // Security token input { pkt << uint8(1); } uint8 secLevel = (*result)[4].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); for(int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; sLog.outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); // user authenticated => turn off autoreg, thus account creating _autoreg = false; } } delete result; } else if(_autoreg) // no account { // check username if(_safelogin.find_first_of(notAllowedChars)!=_safelogin.npos || _safelogin.length()<4) _autoreg = false; // check IP else if(uint32 amountip = sConfig.GetIntDefault("AmountIP", 0)) { QueryResult *result2 = loginDatabase.PQuery("SELECT COUNT(last_ip) FROM account WHERE last_ip = '%s'", GetRemoteAddress().c_str()); if (result2 && (*result2)[0].GetUInt8() >= amountip) { _autoreg = false; delete result2; } } // still all ok if(_autoreg) { ///- Get the password from the account table, upper it, and make the SRP6 calculation std::transform(_safelogin.begin(), _safelogin.end(), _safelogin.begin(), std::towupper); Sha1Hash sha; std::string sI = _safelogin + ":" + _safelogin; sha.UpdateData(sI); sha.Finalize(); BigNumber bn; bn.SetBinary(sha.GetDigest(), sha.GetLength()); uint8 *val = bn.AsByteArray(); std::reverse(val, val+bn.GetNumBytes()); bn.SetBinary(val, bn.GetNumBytes()); const char* rI = bn.AsHexStr(); _SetVSFields(rI); OPENSSL_free((void*)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(), 32); 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 } else // username and/or IP is bad pkt << (uint8) REALM_AUTH_NO_MATCH; } else { // autoreg off in config, account is wrong pkt << (uint8) REALM_AUTH_NO_MATCH; } } SendBuf((char const*)pkt.contents(), pkt.size()); 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)); ///- Continue the SRP6 calculation based on data received from the client BigNumber A; A.SetBinary(lp.A, 32); 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); 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)) { sLog.outBasic("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(); dbRealmServer.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, GetRemoteAddress().c_str(), _localization, _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(); sAuthLogonProof_S proof; memcpy(proof.M2, sha.GetDigest(), 20); proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; proof.unk1 = 0x00800000; proof.unk2 = 0x00; proof.unk3 = 0x00; SendBuf((char *)&proof, sizeof(proof)); ///- Set _authed to true! _authed = true; } else { char data[4]={AUTH_LOGON_PROOF,REALM_AUTH_NO_MATCH,3,0}; SendBuf(data,sizeof(data)); sLog.outBasic("[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 dbRealmServer.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'",_safelogin.c_str()); if(QueryResult *loginfail = dbRealmServer.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(); dbRealmServer.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); sLog.outBasic("[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(); dbRealmServer.escape_string(current_ip); dbRealmServer.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); sLog.outBasic("[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 Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; _os = (const char*)ch->os; if(_os.size() > 4) return false; ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; LoginDatabase.escape_string(_safelogin); // Starting CMD_AUTH_LOGON_CHALLENGE AuthResult result = WOW_FAIL_UNKNOWN0; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::string address = get_remote_address(); LoginDatabase.escape_string(address); QueryResult* qresult = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " // permanent still banned "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", address.c_str()); if (qresult) { result = WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); delete qresult; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) //qresult = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'",_safelogin.c_str()); qresult = LoginDatabase.PQuery("SELECT a.sha_pass_hash,a.id,a.locked,a.last_ip,aa.gmlevel,a.v,a.s FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = '******'", _safelogin.c_str()); if (qresult) { std::string rI = (*qresult)[0].GetCppString(); uint32 accountId = (*qresult)[1].GetUInt32(); uint8 locked = (*qresult)[2].GetUInt8(); std::string lastIP = (*qresult)[3].GetString(); uint8 secLevel = (*qresult)[4].GetUInt8(); std::string databaseV = (*qresult)[5].GetCppString(); std::string databaseS = (*qresult)[6].GetCppString(); bool blockLogin = false; if (sConfig.GetBoolDefault("MultiIPCheck", false)) { int32 iplimit = sConfig.GetIntDefault("MultiIPLimit", 10); int32 multiIPdelay = sConfig.GetIntDefault("MultiIPPeriodInHours", 48); // If a GM account login ignore MultiIP QueryResult* ipcheck = LoginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s' AND id != %u AND last_login > NOW() - INTERVAL %u HOUR ORDER BY last_login DESC;", get_remote_address().c_str(), accountId, multiIPdelay); if (ipcheck) { // build whitelist std::list<uint32> accountsInWhitelist; accountsInWhitelist.clear(); QueryResult* IDsinwhite = LoginDatabase.PQuery("SELECT whitelist FROM multi_IP_whitelist WHERE whitelist LIKE '%|%u|%'", accountId); if (IDsinwhite) { Tokens whitelistaccounts((*IDsinwhite)[0].GetCppString(),'|'); bool isInWhite = false; for (Tokens::const_iterator itr = whitelistaccounts.begin(); itr != whitelistaccounts.end(); ++itr) accountsInWhitelist.push_back(atoi(*itr)); delete IDsinwhite; } do { Field* pFields =ipcheck->Fetch(); uint32 MultiAccountID = pFields[0].GetUInt32(); bool isInWhite = false; for (std::list<uint32>::const_iterator itr = accountsInWhitelist.begin(); itr != accountsInWhitelist.end(); ++itr) { if (*itr == MultiAccountID) isInWhite = true; } if (!isInWhite) { --iplimit; } } while (ipcheck->NextRow()); delete ipcheck; } /* * default case 10 allowed account with same last_ip * we found 9 account with current ip. NOTE: actual account is not in list * 10 - 9 - 1 * ^ current account * ^ account in list * ^ allowed */ if (iplimit < 1) { DEBUG_LOG("[AuthChallenge] Account '%s' is multi IP - '%s'", _login.c_str(), lastIP.c_str()); result = WOW_FAIL_PARENTCONTROL; blockLogin = true; } } ///- If the IP is 'locked', check that the player comes indeed from the correct IP address if (locked == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), lastIP.c_str()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if (strcmp(lastIP.c_str(),get_remote_address().c_str()) ) { DEBUG_LOG("[AuthChallenge] Account IP differs"); result = WOW_FAIL_SUSPENDED; blockLogin = true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!blockLogin) { ///- If the account is banned, reject the logon attempt QueryResult* banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE " "id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)", accountId); if (banresult) { if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { result = WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned account %s (Id: %u) tries to login!", _login.c_str(), accountId); } else { result = WOW_FAIL_SUSPENDED; BASIC_LOG("[AuthChallenge] Temporarily banned account %s (Id: %u) tries to login!",_login.c_str(), accountId); } delete banresult; } else { DEBUG_LOG("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2, bytes are stored as hexstring if (databaseV.size() != s_BYTE_SIZE*2 || databaseS.size() != s_BYTE_SIZE*2) _SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } result = WOW_SUCCESS; _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; BASIC_LOG("[AuthChallenge] account %s (Id: %u) is using '%c%c%c%c' locale (%u)", _login.c_str (), accountId, ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); } } delete qresult; } else if (sConfig.GetBoolDefault("AutoRegistration", false)) { if (_safelogin.find_first_of("\t\v\b\f\a\n\r\\\"\'\? <>[](){}_=+-|/!@#$%^&*~`.,\0") == _safelogin.npos && _safelogin.length() > 3) { QueryResult* checkIPresult = LoginDatabase.PQuery("SELECT COUNT(last_ip) FROM account WHERE last_ip = '%s'",get_remote_address().c_str()); int32 regCount = checkIPresult ? (*checkIPresult)[0].GetUInt32() : 0; if (regCount >= sConfig.GetIntDefault("AutoRegistration.Amount", 1)) { BASIC_LOG("[AuthChallenge] Impossible auto-register account %s, number of auto-registered accouts is %u, but allowed only %u", _safelogin.c_str(),regCount, sConfig.GetIntDefault("AutoRegistration.Amount", 1)); // result = WOW_FAIL_DB_BUSY; result = WOW_FAIL_DISCONNECTED; } else { std::transform(_safelogin.begin(), _safelogin.end(), _safelogin.begin(), std::towupper); Sha1Hash sha; sha.Initialize(); sha.UpdateData(_safelogin); sha.UpdateData(":"); sha.UpdateData(_safelogin); sha.Finalize(); std::string encoded; hexEncodeByteArray(sha.GetDigest(), sha.GetLength(), encoded); LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", _safelogin.c_str(), encoded.c_str()); _SetVSFields(encoded); BASIC_LOG("[AuthChallenge] account %s auto-registered (count %u)!",_safelogin.c_str(), ++regCount); result = WOW_SUCCESS; _accountSecurityLevel = SEC_PLAYER; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; } if (checkIPresult) delete checkIPresult; } } else result = WOW_FAIL_UNKNOWN_ACCOUNT; } pkt << uint8(CMD_AUTH_LOGON_CHALLENGE); pkt << uint8(0x00); pkt << uint8(result); switch (result) { case WOW_SUCCESS: { b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; MANGOS_ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if (securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if (securityFlags & 0x04) // Security token input { pkt << uint8(1); } break; } case WOW_FAIL_UNKNOWN0: case WOW_FAIL_UNKNOWN1: case WOW_FAIL_SUSPENDED: case WOW_FAIL_BANNED: case WOW_FAIL_UNKNOWN_ACCOUNT: case WOW_FAIL_INCORRECT_PASSWORD: case WOW_FAIL_ALREADY_ONLINE: case WOW_FAIL_NO_TIME: case WOW_FAIL_DB_BUSY: case WOW_FAIL_VERSION_INVALID: case WOW_FAIL_VERSION_UPDATE: case WOW_FAIL_INVALID_SERVER: case WOW_FAIL_FAIL_NOACCESS: case WOW_SUCCESS_SURVEY: case WOW_FAIL_PARENTCONTROL: case WOW_FAIL_LOCKED_ENFORCED: case WOW_FAIL_TRIAL_ENDED: case WOW_FAIL_USE_BATTLENET: case WOW_FAIL_TOO_FAST: case WOW_FAIL_CHARGEBACK: case WOW_FAIL_GAME_ACCOUNT_LOCKED: case WOW_FAIL_INTERNET_GAME_ROOM_WITHOUT_BNET: case WOW_FAIL_UNLOCKABLE_LOCK: case WOW_FAIL_DISCONNECTED: break; default: BASIC_LOG("[AuthChallenge] unknown CMD_AUTH_LOGON_CHALLENGE execution result %u!", result); break; } send((char const*)pkt.contents(), pkt.size()); return true; }
int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) { // NOTE: ATM the socket is singlethread, have this in mind ... uint8 digest[20]; uint32 clientSeed; uint32 unk2; uint32 BuiltNumberClient; uint32 id, security; uint8 expansion = 0; LocaleConstant locale; std::string account; Sha1Hash sha1; BigNumber v, s, g, N, x, I; WorldPacket packet, SendAddonPacked; BigNumber K; if (recvPacket.size () < (4 + 4 + 1 + 4 + 20)) { sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size"); return -1; } // Read the content of the packet recvPacket >> BuiltNumberClient; // for now no use recvPacket >> unk2; recvPacket >> account; if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20)) { sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check"); return -1; } recvPacket >> clientSeed; recvPacket.read (digest, 20); DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u", BuiltNumberClient, unk2, account.c_str (), clientSeed); // Get the account information from the realmd database std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below loginDatabase.escape_string (safe_account); // No SQL injection, username escaped. QueryResult *result = loginDatabase.PQuery ("SELECT " "id, " //0 "gmlevel, " //1 "sessionkey, " //2 "last_ip, " //3 "locked, " //4 "sha_pass_hash, " //5 "v, " //6 "s, " //7 "expansion, " //8 "mutetime, " //9 "locale " //10 "FROM account " "WHERE username = '******'", safe_account.c_str ()); // Stop if the account is not found if (!result) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_UNKNOWN_ACCOUNT); SendPacket (packet); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); return -1; } Field* fields = result->Fetch (); expansion = fields[8].GetUInt8 () && sWorld.getConfig (CONFIG_EXPANSION) > 0; N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); g.SetDword (7); I.SetHexStr (fields[5].GetString ()); //In case of leading zeros in the I hash, restore them uint8 mDigest[SHA_DIGEST_LENGTH]; memset (mDigest, 0, SHA_DIGEST_LENGTH); if (I.GetNumBytes () <= SHA_DIGEST_LENGTH) memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ()); std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH); s.SetHexStr (fields[7].GetString ()); sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ()); sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH); sha1.Finalize (); x.SetBinary (sha1.GetDigest (), sha1.GetLength ()); v = g.ModExp (x, N); const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free() const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free() const char* vold = fields[6].GetString (); DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s", sStr, vold, vStr); loginDatabase.PExecute ("UPDATE account " "SET " "v = '0', " "s = '0' " "WHERE username = '******'", safe_account.c_str ()); if (!vold || strcmp (vStr, vold)) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_UNKNOWN_ACCOUNT); SendPacket (packet); delete result; OPENSSL_free ((void*) sStr); OPENSSL_free ((void*) vStr); sLog.outBasic ("WorldSocket::HandleAuthSession: User not logged."); return -1; } OPENSSL_free ((void*) sStr); OPENSSL_free ((void*) vStr); ///- Re-check ip locking (same check as in realmd). if (fields[4].GetUInt8 () == 1) // if ip is locked { if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ())) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_FAILED); SendPacket (packet); delete result; sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); return -1; } } id = fields[0].GetUInt32 (); security = fields[1].GetUInt16 (); K.SetHexStr (fields[2].GetString ()); time_t mutetime = time_t (fields[9].GetUInt64 ()); locale = LocaleConstant (fields[10].GetUInt8 ()); if (locale >= MAX_LOCALE) locale = LOCALE_enUS; delete result; // Re-check account ban (same check as in realmd) QueryResult *banresult = loginDatabase.PQuery ("SELECT " "bandate, " "unbandate " "FROM account_banned " "WHERE id = '%u' " "AND active = 1", id); if (banresult) // if account banned { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_BANNED); SendPacket (packet); delete banresult; sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); return -1; } // Check locked state for server AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit (); if (allowedAccountType > SEC_PLAYER && security < allowedAccountType) { WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); Packet << uint8 (AUTH_UNAVAILABLE); SendPacket (packet); sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough"); return -1; } // Check that Key and account name are the same on client and server Sha1Hash sha; uint32 t = 0; uint32 seed = m_Seed; sha.UpdateData (account); sha.UpdateData ((uint8 *) & t, 4); sha.UpdateData ((uint8 *) & clientSeed, 4); sha.UpdateData ((uint8 *) & seed, 4); sha.UpdateBigNumbers (&K, NULL); sha.Finalize (); if (memcmp (sha.GetDigest (), digest, 20)) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_FAILED); SendPacket (packet); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); return -1; } std::string address = GetRemoteAddress (); DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", account.c_str (), address.c_str ()); // Update the last_ip in the database // No SQL injection, username escaped. loginDatabase.escape_string (address); loginDatabase.PExecute ("UPDATE account " "SET last_ip = '%s' " "WHERE username = '******'", address.c_str (), safe_account.c_str ()); // NOTE ATM the socket is singlethreaded, have this in mind ... ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1); m_Crypt.SetKey (&K); m_Crypt.Init (); // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec ACE_OS::sleep (ACE_Time_Value (0, 10000)); sWorld.AddSession (m_Session); // Create and send the Addon packet if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) SendPacket (SendAddonPacked); return 0; }
/// Logon Proof command handler bool AuthSocket::_HandleLogonProof() { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet sAuthLogonProof_C lp; if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C))) return false; /// <ul><li> If the client has no valid version if (_expversion == NO_VALID_EXP_FLAG) { ///- Check if we have the appropriate patch on the disk sLog.outDebug("Client with invalid version, patching is not implemented"); socket().shutdown(); 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()) { socket().shutdown(); return true; } 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)) { sLog.outBasic("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, socket().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(); if (_expversion & POST_BC_EXP_FLAG)//2.4.3 and 3.1.3 clients (10146 is Chinese build for 3.1.3) { sAuthLogonProof_S proof; memcpy(proof.M2, sha.GetDigest(), 20); proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; proof.unk1 = 0x00800000; proof.unk2 = 0x00; proof.unk3 = 0x00; socket().send((char *)&proof, sizeof(proof)); } else { sAuthLogonProof_S_Old proof; memcpy(proof.M2, sha.GetDigest(), 20); proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; //proof.unk1 = 0x00800000; proof.unk2 = 0x00; //proof.unk3 = 0x00; socket().send((char *)&proof, sizeof(proof)); } ///- Set _authed to true! _authed = true; } else { char data[4]= { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; socket().send(data, sizeof(data)); sLog.outBasic("[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_AutoPtr 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','Trinity realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); sLog.outBasic("[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(socket().get_remote_address().c_str()); LoginDatabase.escape_string(current_ip); LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); sLog.outBasic("[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); } } } } } return true; }
void LogonServer::Run(int argc, char ** argv) { UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); #ifdef WIN32 char * config_file = "configs/logon.conf"; #else char * config_file = (char*)CONFDIR "/logon.conf"; #endif int file_log_level = DEF_VALUE_NOT_SET; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; struct arcemu_option longopts[] = { { "checkconf", arcemu_no_argument, &do_check_conf, 1 }, { "screenloglevel", arcemu_required_argument, &screen_log_level, 1 }, { "fileloglevel", arcemu_required_argument, &file_log_level, 1 }, { "version", arcemu_no_argument, &do_version, 1 }, { "conf", arcemu_required_argument, NULL, 'c' }, { 0, 0, 0, 0 } }; int c; while ((c = arcemu_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': /* Log filename was set */ config_file = new char[strlen(arcemu_optarg)]; strcpy(config_file,arcemu_optarg); break; case 0: break; default: sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--version]\n", argv[0]); return; } } // Startup banner if(!do_version && !do_check_conf) { sLog.Init(-1, 3); } else { sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; } sLog.outString(BANNER, BUILD_TAG, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH); Log.Color(TBLUE); printf("\nCopyright (C) 2008-2010 ArcEmu. http://www.arcemu.org/\n"); printf("This program is free software: you can redistribute it and/or modify\n"); printf("it under the terms of the GNU Affero General Public License as published by\n"); printf("the Free Software Foundation, either version 3 of the License, or\n"); printf("any later version.\n"); printf("This program is distributed in the hope that it will be useful,\n"); printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); printf("GNU Affero General Public License for more details.\n"); printf(" \n"); printf(" `````` \n"); printf(" ArcEmu! `/o/::-:/- \n"); printf(" oho/-.-:yN- \n"); printf(" os+/-.::: \n"); printf(" :ysyoo+:` \n"); printf(" `ohdys/. \n"); printf(" oyho/-` `` \n"); printf(" `shyo+:./ssmdsyo:` \n"); printf(" .shss+:yNMMNNMNmms. \n"); printf(" :ysss+:mNMMMMNNmmds. \n"); printf(" `-//sssoo/:NMNMMMNMNNdy- \n"); printf(" -`/` `omhyyhyyyshNMMNNNMMMNmy: \n"); printf(" :/::-` `sdmdmmNMNMMMMMMNMNNNNms- \n"); printf(" /+++/-.....shdmmNMMNMMMMMMMMMNNNd+ \n"); printf(" ./+oshyhhhddmhdmNMMMMMMMMMMMMNNds. \n"); printf(" `:/:.`````.:+ymmNMMNMMMNMMNNd/ \n"); printf(" -+shmNNMMMNmhy/ \n"); printf(" `..-ods:. \n"); printf(" o:.` \n"); printf(" :-. \n"); printf(" `/-... \n"); printf(" Introducing the emu! --``-/:` \n"); printf(" .:/+:-.-::. \n"); printf(" `.-///:-.` \n"); printf(" Website: http://www.ArcEmu.org \n"); printf(" Forums: http://www.ArcEmu.org/forums/ \n"); printf(" Credits: http://www.ArcEmu.org/credits \n"); printf(" SVN: http://arcemu.info/svn/ \n"); printf(" Have fun! \n"); Log.Line(); #ifdef REPACK sLog.outString("Repack: %s | Author: %s | %s\n", REPACK, REPACK_AUTHOR, REPACK_WEBSITE); #endif sLog.outString("=============================================================================="); sLog.outString(""); if(do_version) return; if(do_check_conf) { printf("Checking config file: %s\n", config_file); if(Config.MainConfig.SetSource(config_file, true)) printf(" Passed without errors.\n"); else printf(" Encountered one or more errors.\n"); /* Remved useless die directive */ /* string die; if(Config.MainConfig.GetString("die", "msg", &die) || Config.MainConfig.GetString("die2", "msg", &die)) printf("Die directive received: %s", die.c_str()); */ return; } sLog.outString("The key combination <Ctrl-C> will safely shut down the server at any time."); sLog.outString(""); Log.Notice("System","Initializing Random Number Generators..."); Log.Notice("Config", "Loading Config Files..."); if(!Rehash()) return; Log.Notice("ThreadMgr", "Starting..."); ThreadPool.Startup(); if(!startdb()) return; Log.Notice("AccountMgr", "Starting..."); new AccountMgr; new IPBanner; Log.Notice("InfoCore", "Starting..."); new InformationCore; new PatchMgr; Log.Notice("AccountMgr", "Precaching accounts..."); sAccountMgr.ReloadAccounts(true); Log.Notice("AccountMgr", "%u accounts are loaded and ready.", sAccountMgr.GetCount()); Log.Line(); // Spawn periodic function caller thread for account reload every 10mins int atime = Config.MainConfig.GetIntDefault("Rates", "AccountRefresh",600); atime *= 1000; //SpawnPeriodicCallThread(AccountMgr, AccountMgr::getSingletonPtr(), &AccountMgr::ReloadAccountsCallback, time); PeriodicFunctionCaller<AccountMgr> * pfc = new PeriodicFunctionCaller<AccountMgr>(AccountMgr::getSingletonPtr(), &AccountMgr::ReloadAccountsCallback, atime); ThreadPool.ExecuteTask(pfc); // Load conf settings.. uint32 cport = Config.MainConfig.GetIntDefault("Listen", "RealmListPort", 3724); uint32 sport = Config.MainConfig.GetIntDefault("Listen", "ServerPort", 8093); //uint32 threadcount = Config.MainConfig.GetIntDefault("Network", "ThreadCount", 5); //uint32 threaddelay = Config.MainConfig.GetIntDefault("Network", "ThreadDelay", 20); string host = Config.MainConfig.GetStringDefault("Listen", "Host", "0.0.0.0"); string shost = Config.MainConfig.GetStringDefault("Listen", "ISHost", host.c_str()); min_build = Config.MainConfig.GetIntDefault("Client", "MinBuild", 6180); max_build = Config.MainConfig.GetIntDefault("Client", "MaxBuild", 6999); string logon_pass = Config.MainConfig.GetStringDefault("LogonServer", "RemotePassword", "r3m0t3b4d"); Sha1Hash hash; hash.UpdateData(logon_pass); hash.Finalize(); memcpy(sql_hash, hash.GetDigest(), 20); ThreadPool.ExecuteTask(new LogonConsoleThread); new SocketMgr; new SocketGarbageCollector; sSocketMgr.SpawnWorkerThreads(); ListenSocket<AuthSocket> * cl = new ListenSocket<AuthSocket>(host.c_str(), cport); ListenSocket<LogonCommServerSocket> * sl = new ListenSocket<LogonCommServerSocket>(shost.c_str(), sport); // Spawn auth listener // Spawn interserver listener bool authsockcreated = cl->IsOpen(); bool intersockcreated = sl->IsOpen(); #ifdef WIN32 if(authsockcreated) ThreadPool.ExecuteTask(cl); if(intersockcreated) ThreadPool.ExecuteTask(sl); #endif // hook signals sLog.outString("Hooking signals..."); signal(SIGINT, _OnSignal); signal(SIGTERM, _OnSignal); signal(SIGABRT, _OnSignal); #ifdef _WIN32 signal(SIGBREAK, _OnSignal); #else signal(SIGHUP, _OnSignal); #endif /* write pid file */ FILE * fPid = fopen("logonserver.pid", "w"); if(fPid) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf(fPid, "%u", (unsigned int)pid); fclose(fPid); } uint32 loop_counter = 0; //ThreadPool.Gobble(); sLog.outString("Success! Ready for connections"); while(mrunning && authsockcreated && intersockcreated) { if(!(++loop_counter % 20)) // 20 seconds CheckForDeadSockets(); if(!(loop_counter%300)) // 5mins ThreadPool.IntegrityCheck(); if(!(loop_counter%5)) { sInfoCore.TimeoutSockets(); sSocketGarbageCollector.Update(); CheckForDeadSockets(); // Flood Protection UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); } PatchMgr::getSingleton().UpdateJobs(); Sleep(1000); } sLog.outString("Shutting down..."); signal(SIGINT, 0); signal(SIGTERM, 0); signal(SIGABRT, 0); #ifdef _WIN32 signal(SIGBREAK, 0); #else signal(SIGHUP, 0); #endif pfc->kill(); cl->Close(); sl->Close(); sSocketMgr.CloseAll(); #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif sLogonConsole.Kill(); delete LogonConsole::getSingletonPtr(); // kill db sLog.outString("Waiting for database to close.."); sLogonSQL->EndThreads(); sLogonSQL->Shutdown(); delete sLogonSQL; ThreadPool.Shutdown(); // delete pid file remove("logonserver.pid"); delete AccountMgr::getSingletonPtr(); delete InformationCore::getSingletonPtr(); delete PatchMgr::getSingletonPtr(); delete IPBanner::getSingletonPtr(); delete SocketMgr::getSingletonPtr(); delete SocketGarbageCollector::getSingletonPtr(); delete pfc; delete cl; delete sl; printf("Shutdown complete.\n"); }
void WorldSocket::InformationRetreiveCallback(WorldPacket & recvData, uint32 requestid) { if(requestid != mRequestID) return; uint32 error; recvData >> error; if(error != 0 || pAuthenticationPacket == NULL) { // something happened wrong @ the logon server OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D"); return; } // Extract account information from the packet. string AccountName; const string * ForcedPermissions; uint32 AccountID; string GMFlags; uint8 AccountFlags; string lang = "enUS"; uint32 i; recvData >> AccountID >> AccountName >> GMFlags >> AccountFlags; ForcedPermissions = sLogonCommHandler.GetForcedPermissions(AccountName); if( ForcedPermissions != NULL ) GMFlags.assign(ForcedPermissions->c_str()); sLog.outDebug( " >> got information packet from logon: `%s` ID %u (request %u)", AccountName.c_str(), AccountID, mRequestID); // sLog.outColor(TNORMAL, "\n"); mRequestID = 0; // Pull the session key. uint8 K[40]; recvData.read(K, 40); BigNumber BNK; BNK.SetBinary(K, 40); uint8 *key = new uint8[20]; WowCrypt::GenerateKey(key, K); // Initialize crypto. _crypt.SetKey(key, 20); _crypt.Init(); delete [] key; //checking if player is already connected //disconnect corrent player and login this one(blizzlike) if(recvData.rpos() != recvData.wpos()) recvData.read((uint8*)lang.data(), 4); WorldSession *session = sWorld.FindSession( AccountID ); if( session) { // AUTH_FAILED = 0x0D session->Disconnect(); // clear the logout timer so he times out straight away session->SetLogoutTimer(1); // we must send authentication failed here. // the stupid newb can relog his client. // otherwise accounts dupe up and disasters happen. OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15"); return; } Sha1Hash sha; uint8 digest[20]; pAuthenticationPacket->read(digest, 20); uint32 t = 0; if( m_fullAccountName == NULL ) // should never happen ! sha.UpdateData(AccountName); else { sha.UpdateData(*m_fullAccountName); // this is unused now. we may as well free up the memory. delete m_fullAccountName; m_fullAccountName = NULL; } sha.UpdateData((uint8 *)&t, 4); sha.UpdateData((uint8 *)&mClientSeed, 4); sha.UpdateData((uint8 *)&mSeed, 4); sha.UpdateBigNumbers(&BNK, NULL); sha.Finalize(); if (memcmp(sha.GetDigest(), digest, 20)) { // AUTH_UNKNOWN_ACCOUNT = 21 OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15"); return; } // Allocate session WorldSession * pSession = new WorldSession(AccountID, AccountName, this); mSession = pSession; ASSERT(mSession); pSession->deleteMutex.Acquire(); // Set session properties pSession->SetClientBuild(mClientBuild); pSession->LoadSecurity(GMFlags); pSession->SetAccountFlags(AccountFlags); pSession->m_lastPing = (uint32)UNIXTIME; pSession->language = sLocalizationMgr.GetLanguageId(lang); if(recvData.rpos() != recvData.wpos()) recvData >> pSession->m_muted; for(uint32 i = 0; i < 8; ++i) pSession->SetAccountData(i, NULL, true, 0); // queue the account loading /*AsyncQuery * aq = new AsyncQuery( new SQLClassCallbackP1<World, uint32>(World::getSingletonPtr(), &World::LoadAccountDataProc, AccountID) ); aq->AddQuery("SELECT * FROM account_data WHERE acct = %u", AccountID); CharacterDatabase.QueueAsyncQuery(aq);*/ if(sWorld.m_useAccountData) { QueryResult * pResult = CharacterDatabase.Query("SELECT * FROM account_data WHERE acct = %u", AccountID); if( pResult == NULL ) CharacterDatabase.Execute("INSERT INTO account_data VALUES(%u, '', '', '', '', '', '', '', '', '')", AccountID); else { size_t len; const char * data; char * d; for(i = 0; i < 8; ++i) { data = pResult->Fetch()[1+i].GetString(); len = data ? strlen(data) : 0; if(len > 1) { d = new char[len+1]; memcpy(d, data, len+1); pSession->SetAccountData(i, d, true, (uint32)len); } } delete pResult; } } Log.Debug("Auth", "%s from %s:%u [%ums]", AccountName.c_str(), GetRemoteIP().c_str(), GetRemotePort(), _latency); #ifdef SESSION_CAP if( sWorld.GetSessionCount() >= SESSION_CAP ) { OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D"); Disconnect(); return; } #endif // Check for queue. if( (sWorld.GetSessionCount() < sWorld.GetPlayerLimit()) || pSession->HasGMPermissions() ) { Authenticate(); } else { // Queued, sucker. uint32 Position = sWorld.AddQueuedSocket(this); mQueued = true; Log.Debug("Queue", "%s added to queue in position %u", AccountName.c_str(), Position); // Send packet so we know what we're doing UpdateQueuePosition(Position); } pSession->deleteMutex.Release(); }
void WorldSocket::InformationRetreiveCallback(WorldPacket & recvData, uint32 requestid) { if(requestid != mRequestID) return; uint32 error; recvData >> error; if(error != 0) { // something happened wrong @ the logon server OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D"); return; } // Extract account information from the packet. string AccountName; uint32 AccountID; string GMFlags; uint32 AccountFlags; recvData >> AccountID >> AccountName >> GMFlags >> AccountFlags; sLog.outDebug( " >> got information packet from logon: `%s` ID %u (request %u)", AccountName.c_str(), AccountID, mRequestID); // sLog.outColor(TNORMAL, "\n"); mRequestID = 0; // Pull the session key. uint8 K[40]; recvData.read(K, 40); BigNumber BNK; BNK.SetBinary(K, 40); // Initialize crypto. _crypt.SetKey(K, 40); _crypt.Init(); Session * session = sClientMgr.CreateSession(AccountID); if(session == NULL) { /* we are already logged in. send auth failed. (if anyone has a better error lemme know :P) */ OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D"); return; } m_session = session; session->m_socket = this; Sha1Hash sha; uint8 digest[20]; pAuthenticationPacket->read(digest, 20); uint32 t = 0; sha.UpdateData(AccountName); sha.UpdateData((uint8 *)&t, 4); sha.UpdateData((uint8 *)&mClientSeed, 4); sha.UpdateData((uint8 *)&mSeed, 4); sha.UpdateBigNumbers(&BNK, NULL); sha.Finalize(); if (memcmp(sha.GetDigest(), digest, 20)) { // AUTH_UNKNOWN_ACCOUNT = 21 OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15"); return; } // Allocate session m_session->m_accountFlags = AccountFlags; m_session->m_GMPermissions = GMFlags; m_session->m_accountId = AccountID; m_session->m_latency = _latency; m_session->m_accountName = AccountName; Log.Notice("Auth", "%s from %s:%u [%ums]", AccountName.c_str(), GetRemoteIP().c_str(), GetRemotePort(), _latency); Authenticate(); }
void AuthSocket::HandleChallenge() { // No header if(GetReadBuffer()->GetSize() < 4) return; if(sInfoCore.GetRealmMap().empty()) { // If we lack a realm to connect to, block em, it's better then making them sit and get locked into an empty list. SendChallengeError(CE_IPBAN); return; } // Check the rest of the packet is complete. uint8 * ReceiveBuffer = (uint8*)GetReadBuffer()->GetBufferOffset(); uint16 full_size = *(uint16*)&ReceiveBuffer[2]; DEBUG_LOG("AuthChallenge","got header, body is 0x%02X bytes", full_size); if(GetReadBuffer()->GetSize() < uint32(full_size+4)) return; // Copy the data into our cached challenge structure if(full_size > sizeof(sAuthLogonChallenge_C)) { Disconnect(); return; } DEBUG_LOG("AuthChallenge","got full packet."); GetReadBuffer()->Read(&m_challenge, full_size + 4); // Check client build. if(GetBuild() > LogonServer::getSingleton().max_build) { SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } if(GetBuild() < LogonServer::getSingleton().min_build) { // can we patch? char flippedloc[5] = {0,0,0,0,0}; flippedloc[0] = m_challenge.country[3]; flippedloc[1] = m_challenge.country[2]; flippedloc[2] = m_challenge.country[1]; flippedloc[3] = m_challenge.country[0]; m_patch = PatchMgr::getSingleton().FindPatchForClient(GetBuild(), flippedloc); if(m_patch == NULL) { // could not find a valid patch SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } DEBUG_LOG("Patch", "Selected patch %u%s for client.", m_patch->Version,m_patch->Locality); BigNumber unk; unk.SetRand(128); uint8 response[119] = { 0x00, 0x00, 0x00, 0x72, 0x50, 0xa7, 0xc9, 0x27, 0x4a, 0xfa, 0xb8, 0x77, 0x80, 0x70, 0x22, 0xda, 0xb8, 0x3b, 0x06, 0x50, 0x53, 0x4a, 0x16, 0xe2, 0x65, 0xba, 0xe4, 0x43, 0x6f, 0xe3, 0x29, 0x36, 0x18, 0xe3, 0x45, 0x01, 0x07, 0x20, 0x89, 0x4b, 0x64, 0x5e, 0x89, 0xe1, 0x53, 0x5b, 0xbd, 0xad, 0x5b, 0x8b, 0x29, 0x06, 0x50, 0x53, 0x08, 0x01, 0xb1, 0x8e, 0xbf, 0xbf, 0x5e, 0x8f, 0xab, 0x3c, 0x82, 0x87, 0x2a, 0x3e, 0x9b, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x32, 0xa3, 0x49, 0x76, 0x5c, 0x5b, 0x35, 0x9a, 0x93, 0x3c, 0x6f, 0x3c, 0x63, 0x6d, 0xc0, 0x00 }; Send(response, 119); return; } // Check for a possible IP ban on this client. BAN_STATUS ipb = IPBanner::getSingleton().CalculateBanStatus(GetRemoteAddress()); switch(ipb) { case BAN_STATUS_PERMANENT_BAN: SendChallengeError(CE_ACCOUNT_CLOSED); return; case BAN_STATUS_TIME_LEFT_ON_BAN: SendChallengeError(CE_ACCOUNT_FREEZED); return; default: break; } // Null-terminate the account string if(m_challenge.I_len >= 0x50) { Disconnect(); return; } m_challenge.I[m_challenge.I_len] = 0; AccountName = (char*)&m_challenge.I; string::size_type i = AccountName.rfind("#"); if( i != string::npos ) { printf("# ACCOUNTNAME!\n"); return; } // Look up the account information m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { DEBUG_LOG("AuthChallenge","Account Name: \"%s\" - Account state: INVALID", AccountName.c_str()); // Non-existant account SendChallengeError(CE_NO_ACCOUNT); return; } // Check that the account isn't banned. if(m_account->Banned == 1) { SendChallengeError(CE_ACCOUNT_CLOSED); Log.Notice("AuthChallenge","Account Name: \"%s\" - Account state: CLOSED", AccountName.c_str()); return; } else if(m_account->Banned > 0) { SendChallengeError(CE_ACCOUNT_FREEZED); Log.Notice("AuthChallenge","Account Name: \"%s\" - Account state: FROZEN (%u)", AccountName.c_str(), m_account->Banned); return; } else Log.Notice("AuthChallenge","Account Name: \"%s\" - Account state: OK", AccountName.c_str()); // update cached locale if(!m_account->forcedLocale) { char temp[4]; temp[0] = m_challenge.country[3]; temp[1] = m_challenge.country[2]; temp[2] = m_challenge.country[1]; temp[3] = m_challenge.country[0]; *(uint32*)&m_account->Locale[0] = *(uint32*)temp; } Sha1Hash sha; //uint32 tc = s.GetNumBytes(); sha.UpdateData( s.AsByteArray(), 32 ); sha.UpdateData( m_account->SrpHash, 20 ); sha.Finalize(); BigNumber x; x.SetBinary( sha.GetDigest(), sha.GetLength() ); v = g.ModExp(x, N); b.SetRand(152); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk; unk.SetRand(128); uint8 response[200]; uint32 c = 0; response[c] = 0; c += 1; response[c] = 0; c += 1; response[c] = CE_SUCCESS; c += 1; memcpy(&response[c], B.AsByteArray(), 32); c += 32; response[c] = 1; c += 1; response[c] = g.AsByteArray()[0]; c += 1; response[c] = 32; c += 1; memcpy(&response[c], N.AsByteArray(), 32); c += 32; memcpy(&response[c], s.AsByteArray(), s.GetNumBytes()); c += s.GetNumBytes(); memcpy(&response[c], unk.AsByteArray(), 16); c += 16; response[c] = 0; c += 1; Send(response, c); DEBUG_LOG("AuthSocket","Sending Success Response"); }
/// 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; }
int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) { // NOTE: ATM the socket is singlethread, have this in mind ... uint8 digest[20]; uint32 clientSeed; uint32 unk2; uint32 BuiltNumberClient; uint32 id, security; //uint8 expansion = 0; LocaleConstant locale; std::string account; Sha1Hash sha1; BigNumber v, s, g, N; WorldPacket packet, SendAddonPacked; BigNumber K; // Read the content of the packet recvPacket >> BuiltNumberClient; recvPacket >> unk2; recvPacket >> account; recvPacket >> clientSeed; recvPacket.read (digest, 20); DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u", BuiltNumberClient, unk2, account.c_str (), clientSeed); // Check the version of client trying to connect if (!IsAcceptableClientBuild(BuiltNumberClient)) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_VERSION_MISMATCH); SendPacket (packet); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch)."); return -1; } // Get the account information from the realmd database std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below LoginDatabase.escape_string (safe_account); // No SQL injection, username escaped. QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT " "id, " //0 "gmlevel, " //1 "sessionkey, " //2 "last_ip, " //3 "locked, " //4 "v, " //5 "s, " //6 "expansion, " //7 "mutetime, " //8 "locale " //9 "FROM account " "WHERE username = '******'", safe_account.c_str ()); // Stop if the account is not found if (!result) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_UNKNOWN_ACCOUNT); SendPacket (packet); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); return -1; } Field* fields = result->Fetch (); uint8 expansion = fields[7].GetUInt8(); uint32 world_expansion = sWorld.getConfig(CONFIG_EXPANSION); if (expansion > world_expansion) expansion = world_expansion; //expansion = ((sWorld.getConfig(CONFIG_EXPANSION) > fields[7].GetUInt8()) ? fields[7].GetUInt8() : sWorld.getConfig(CONFIG_EXPANSION)); N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); g.SetDword (7); v.SetHexStr(fields[5].GetString()); s.SetHexStr (fields[6].GetString ()); const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free() const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free() DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s", sStr, vStr); OPENSSL_free ((void*) sStr); OPENSSL_free ((void*) vStr); // Re-check ip locking (same check as in realmd). if (fields[4].GetUInt8 () == 1) // if ip is locked { if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ())) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_FAILED); SendPacket (packet); sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); return -1; } } id = fields[0].GetUInt32 (); security = fields[1].GetUInt16 (); K.SetHexStr (fields[2].GetString ()); time_t mutetime = time_t (fields[8].GetUInt64 ()); locale = LocaleConstant (fields[9].GetUInt8 ()); if (locale >= MAX_LOCALE) locale = LOCALE_enUS; // Re-check account ban (same check as in realmd) QueryResult_AutoPtr banresult = LoginDatabase.PQuery ("SELECT " "bandate, " "unbandate " "FROM account_banned " "WHERE id = '%u' " "AND active = 1", id); if (banresult) // if account banned { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_BANNED); SendPacket (packet); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); return -1; } // Check locked state for server sWorld.UpdateAllowedSecurity(); AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit (); sLog.outDebug("Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security)); if (allowedAccountType > SEC_PLAYER && security < allowedAccountType) { WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); Packet << uint8 (AUTH_UNAVAILABLE); SendPacket (packet); sLog.outDetail ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); return -1; } // Check that Key and account name are the same on client and server Sha1Hash sha; uint32 t = 0; uint32 seed = m_Seed; sha.UpdateData (account); sha.UpdateData ((uint8 *) & t, 4); sha.UpdateData ((uint8 *) & clientSeed, 4); sha.UpdateData ((uint8 *) & seed, 4); sha.UpdateBigNumbers (&K, NULL); sha.Finalize (); if (memcmp (sha.GetDigest (), digest, 20)) { packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet << uint8 (AUTH_FAILED); SendPacket (packet); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); return -1; } std::string address = GetRemoteAddress(); DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", account.c_str(), address.c_str()); // Update the last_ip in the database // No SQL injection, username escaped. LoginDatabase.escape_string (address); LoginDatabase.PExecute ("UPDATE account " "SET last_ip = '%s' " "WHERE username = '******'", address.c_str(), safe_account.c_str()); // NOTE ATM the socket is single-threaded, have this in mind ... ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1); m_Crypt.SetKey(&K); m_Crypt.Init(); // Sleep this Network thread for uint32 sleepTime = sWorld.getConfig(CONFIG_SESSION_ADD_DELAY); ACE_OS::sleep(ACE_Time_Value (0, sleepTime)); sWorld.AddSession (m_Session); // Create and send the Addon packet if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) SendPacket(SendAddonPacked); return 0; }