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); }
void AuthSocket::HandleReconnectChallenge() { // No header if(readBuffer.GetContiguiousBytes() < 4) return; // Check the rest of the packet is complete. uint8* ReceiveBuffer = /*GetReadBuffer(0)*/(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) return; // Copy the data into our cached challenge structure if((size_t)(full_size + 4) > sizeof(sAuthLogonChallenge_C)) { Disconnect(); return; } LOG_DEBUG("[AuthChallenge] got full packet."); memcpy(&m_challenge, ReceiveBuffer, full_size + 4); //RemoveReadBufferBytes(full_size + 4, false); readBuffer.Read(&m_challenge, full_size + 4); // Check client build. if(m_challenge.build > LogonServer::getSingleton().max_build || m_challenge.build < LogonServer::getSingleton().min_build) { SendChallengeError(CE_WRONG_BUILD_NUMBER); 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; } /* buffer overflow thing */ if(m_challenge.I_len >= 50) { Disconnect(); return; } // Null-terminate the account string m_challenge.I[m_challenge.I_len] = 0; // Clear the shitty hash (for server) /* size_t i = 0; for( i = m_challenge.I_len; i >= 0; --i ) { if( m_challenge.I[i] == '#' ) { m_challenge.I[i] = '\0'; break; } }*/ // Look up the account information string AccountName = (char*)&m_challenge.I; 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; } if(!m_account->SessionKey) { SendChallengeError(CE_SERVER_FULL); return; } /** burlex: this is pure speculation, I really have no idea what this does :p * just guessed the md5 because it was 16 byte blocks. */ MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, m_account->SessionKey, 40); uint8 buffer[20]; MD5_Final(buffer, &ctx); ByteBuffer buf; buf << uint16(2); buf.append(buffer, 20); buf << uint64(0); buf << uint64(0); Send(buf.contents(), 34); }
void AuthSocket::HandleReconnectChallenge() { // No header if(GetReadBuffer()->GetSize() < 4) return; // Check the rest of the packet is complete. uint8 * ReceiveBuffer = (uint8*)GetReadBuffer()->GetBufferOffset(); uint16 full_size = *(uint16*)&ReceiveBuffer[2]; DEBUG_LOG("ReconnectChallenge","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((size_t)(full_size+4) > sizeof(sAuthLogonChallenge_C)) { Disconnect(); return; } DEBUG_LOG("ReconnectChallenge", "got full packet."); memcpy(&m_challenge, ReceiveBuffer, full_size + 4); GetReadBuffer()->Read(&m_challenge, full_size + 4); // Check client build. if(m_challenge.build > LogonServer::getSingleton().max_build || m_challenge.build < LogonServer::getSingleton().min_build) { SendChallengeError(CE_WRONG_BUILD_NUMBER); 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 >= 50 ) { Disconnect(); return; } m_challenge.I[m_challenge.I_len] = 0; // Look up the account information AccountName = (char*)&m_challenge.I; Log.Notice("ReconnectChallenge","Account Name: \"%s\"", AccountName.c_str()); m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { DEBUG_LOG("ReconnectChallenge","Invalid account."); // 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("ReconnectChallenge","Account banned state = %u", m_account->Banned); return; } else if(m_account->Banned > 0) { SendChallengeError(CE_ACCOUNT_FREEZED); Log.Notice("ReconnectChallenge","Account banned state = %u", m_account->Banned); return; } else DEBUG_LOG("ReconnectChallenge","Account banned state = %u", m_account->Banned); if(!m_account->SessionKey) { SendChallengeError(CE_SERVER_FULL); return; } /** Mangos figured this out, thanks for the structure. */ ///- Sending response if(GetBuild() <= 6005) { MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, m_account->SessionKey, 40); uint8 buffer[20]; MD5_Final(buffer, &ctx); ByteBuffer buf; buf << uint16(2); buf.append(buffer, 20); buf << uint64(0); buf << uint64(0); Send(buf.contents(), 34); } else { ByteBuffer pkt; pkt << (uint8) 0x02; //ReconnectChallenge pkt << (uint8) 0x00; rs.SetRand(16*8); pkt.append(rs.AsByteBuffer()); // 16 bytes random pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros Send(pkt.contents(), uint32(pkt.size())); } }
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"); }
void AuthSocket::HandleChallenge() { // No header if(GetReadBuffer().GetContiguiousBytes() < 4) return; // Check the rest of the packet is complete. uint8 * ReceiveBuffer = (uint8*)GetReadBuffer().GetBufferStart(); #ifdef USING_BIG_ENDIAN uint16 full_size = swap16(*(uint16*)&ReceiveBuffer[2]); #else uint16 full_size = *(uint16*)&ReceiveBuffer[2]; #endif sLog.outDetail("[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; } sLog.outDebug("[AuthChallenge] got full packet."); //memcpy(&m_challenge, ReceiveBuffer, full_size + 4); //RemoveReadBufferBytes(full_size + 4, true); GetReadBuffer().Read(&m_challenge, full_size + 4); //#ifdef USING_BIG_ENDIAN // uint16 build = swap16(m_challenge.build); // printf("Build: %u\n", build); //#endif // Check client build. #ifdef USING_BIG_ENDIAN uint16 build = swap16(m_challenge.build); #else uint16 build = m_challenge.build; #endif // Check client build. if(build > LogonServer::getSingleton().max_build) { // wtf? 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 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()); 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; // Clear the shitty hash (for server) string AccountName = (char*)&m_challenge.I; string::size_type i = AccountName.rfind("#"); if( i != string::npos ) { printf("# ACCOUNTNAME!\n"); return; //AccountName.erase( i ); } // Look up the account information sLog.outDebug("[AuthChallenge] Account Name: \"%s\"", AccountName.c_str()); m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { sLog.outDebug("[AuthChallenge] Invalid account."); // Non-existant account SendChallengeError(CE_NO_ACCOUNT); return; } sLog.outDebug("[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; } 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); }
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); }
void AuthSocket::HandleChallenge() { // No header if(!HasBytes(4)) return; // Check the rest of the packet is complete. uint16 full_size = *(uint16*)&ReceiveBuffer[2]; sLog.outDetail("[AuthChallenge] got header, body is 0x%02X bytes", full_size); if(!HasBytes(full_size)) return; // Copy the data into our cached challenge structure if(full_size > sizeof(sAuthLogonChallenge_C)) { Disconnect(); return; } sLog.outDebug("[AuthChallenge] got full packet."); memcpy(&m_challenge, ReceiveBuffer, full_size + 4); EraseReceiveBytes(full_size+4); // Check client build. if(m_challenge.build > LogonServer::getSingleton().max_build || m_challenge.build < LogonServer::getSingleton().min_build) { SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } // Check for a possible IP ban on this client. #ifdef WIN32 BAN_STATUS ipb = IPBanner::getSingleton().CalculateBanStatus(ConnectedPeer.sin_addr.S_un.S_addr); #else BAN_STATUS ipb = IPBanner::getSingleton().CalculateBanStatus(RetreiveClientIP()); #endif switch(ipb) { case BAN_STATUS_PERMANANT_BAN: SendChallengeError(CE_ACCOUNT_CLOSED); return; case BAN_STATUS_TIME_LEFT_ON_BAN: SendChallengeError(CE_ACCOUNT_FREEZED); return; } // Null-terminate the account string m_challenge.I[m_challenge.I_len] = 0; // Look up the account information string AccountName = (char*)&m_challenge.I; sLog.outDebug("[AuthChallenge] Account Name: \"%s\"", AccountName.c_str()); m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { sLog.outDebug("[AuthChallenge] Invalid account."); // Non-existant account SendChallengeError(CE_NO_ACCOUNT); return; } sLog.outDebug("[AuthChallenge] Account banned state = %u", m_account->Banned); // Don't update when IP banned, but update anyway if it's an account ban AccountMgr::getSingleton().UpdateAccountLastIP(m_account->AccountId, RetreiveClientIP()); // 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; } // We've passed all initial tests if we're here, lets build the response packet. Sha1Hash I; I.UpdateData((m_account->Username + ":" + m_account->Password)); I.Finalize(); sLog.outDebug("[AuthChallenge] UserPass hash: %X", I.GetDigest()); Sha1Hash sha; uint32 tc = s.GetNumBytes(); sha.UpdateData( s.AsByteArray(), 32 ); sha.UpdateData( I.GetDigest(), 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; SendArray(response, c, FALSE); }
void AuthSocket::HandleProof() { if(!m_account || !HasBytes(sizeof(sAuthLogonProof_C))) return ; sLog.outDebug("[AuthLogonProof] Interleaving and checking proof..."); sAuthLogonProof_C lp; ReadBytes((u8*)&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(m_account->Username); 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); sLog.outDebug("[AuthLogonProof] M1 values don't match."); return; } // Store sessionkey BigNumber * bs = new BigNumber(m_sessionkey); sInfoCore.SetSessionKey(m_account->AccountId, bs); // let the client know sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &m_sessionkey, 0); sha.Finalize(); SendProofError(0, sha.GetDigest()); sLog.outDebug("[AuthLogonProof] Authentication Success."); // we're authenticated now :) m_authenticated = 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_BattleNet)) { 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 up to 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; if (AccountName.substr(0, 1) == "?") { if (AccountName.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?") != string::npos) { LOG_ERROR("[AuthChallenge]: Tried to create account with illegal characters."); SendChallengeError(CE_NO_ACCOUNT); //Well f**k you for editing the files! return; } int pass_start = AccountName.find("?", 1) + 1; if (pass_start < 4) //No username { LOG_ERROR("[AuthChallenge] Tried to create account with no account name."); SendChallengeError(CE_NO_ACCOUNT); return; } int pass_end = AccountName.rfind("?"); if (pass_end <= pass_start) //No password { LOG_ERROR("[AuthChallenge] Tried to create account with no password."); SendChallengeError(CE_NO_ACCOUNT); return; } int name_len = pass_start - 2; int pass_len = pass_end - pass_start; string username = AccountName.substr(1, name_len); string password = AccountName.substr(pass_start, pass_len); m_account = AccountMgr::getSingleton().GetAccount(username); if (m_account != 0) { LOG_ERROR("[AuthChallenge] Account creation failed: account name already taken."); SendChallengeError(CE_ACCOUNT_IN_USE); return; } string cmd = username + " " + password + " NULL"; //Prepare command for CreateAccount char acct[50]; memcpy(acct, cmd.c_str(), 50); //CreateAccount doesn't take const char* LogonConsole::getSingleton().CreateAccount(acct); SendChallengeError(CE_SERVER_FULL); //Success! LOG_BASIC("[AuthChallenge] Client %s has created an account with name: \"%s\"", GetRemoteIP().c_str(), username.c_str()); return; } if (AccountName.substr(0, 1) == "&") { if (AccountName.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?.~&_-") != string::npos) { LOG_ERROR("[AuthChallenge]: Tried to update account with illegal chars. %s", AccountName.c_str()); SendChallengeError(CE_NO_ACCOUNT); //Well f**k you for editing the files! return; } int pass_start = AccountName.find("&", 1) + 1; if (pass_start < 4) //No username { LOG_ERROR("[AuthChallenge] Tried to update account with no account name."); SendChallengeError(CE_NO_ACCOUNT); return; } int pass_end = AccountName.rfind("&"); if (pass_end <= pass_start) //No password { LOG_ERROR("[AuthChallenge] Tried to update account with no email."); SendChallengeError(CE_NO_ACCOUNT); return; } int name_len = pass_start - 2; int pass_len = pass_end - pass_start; string username = AccountName.substr(1, name_len); string email = AccountName.substr(pass_start, pass_len); for (uint8 i = 0; i < email.length(); i++) { if (email[i] == '~') { email[i] = '@'; break; } } m_account = AccountMgr::getSingleton().GetAccount(username); if (m_account == 0) { LOG_ERROR("[AuthChallenge] Account update failed: account does not exist."); SendChallengeError(CE_ACCOUNT_IN_USE); return; } std::stringstream query; query << "UPDATE `accounts` SET `email` = '" << email << "' WHERE `login` = '" << username << "' AND `email` = 'NULL';"; sLogonSQL->WaitExecuteNA(query.str().c_str()); SendChallengeError(CE_SERVER_FULL); //Success! return; } 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(GetReadBufferSize() < sizeof(sAuthLogonProof_C)) return ; // patch if(m_patch&&!m_account) { RemoveReadBufferBytes(75,false); sLog.outDebug("[AuthLogonProof] Intitiating PatchJob"); uint8 bytes[2] = {0x01,0x0a}; Send(bytes,2); PatchMgr::getSingleton().InitiatePatch(m_patch, this); return; } if(!m_account) return; sLog.outDebug("[AuthLogonProof] Interleaving and checking proof..."); sAuthLogonProof_C lp; Read(sizeof(sAuthLogonProof_C), (uint8*)&lp); 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); sLog.outDebug("[AuthLogonProof] M1 values don't match."); 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()); sLog.outDebug("[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); }
void AuthSocket::HandleChallenge() { // No header if(GetReadBufferSize() < 4) return; // Check the rest of the packet is complete. uint8 * ReceiveBuffer = this->GetReadBuffer(0); uint16 full_size = *(uint16*)&ReceiveBuffer[2]; sLog.outDetail("[AuthChallenge] got header, body is 0x%02X bytes", full_size); if(GetReadBufferSize() < uint32(full_size+4)) return; // Copy the data into our cached challenge structure if(full_size > sizeof(sAuthLogonChallenge_C)) { Disconnect(); return; } sLog.outDebug("[AuthChallenge] got full packet."); memcpy(&m_challenge, ReceiveBuffer, full_size + 4); RemoveReadBufferBytes(full_size + 4, true); // Check client build. if(m_challenge.build > LogonServer::getSingleton().max_build || m_challenge.build < LogonServer::getSingleton().min_build) { SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } // Check for a possible IP ban on this client. BAN_STATUS ipb = IPBanner::getSingleton().CalculateBanStatus(GetRemoteAddress()); switch(ipb) { case BAN_STATUS_PERMANANT_BAN: SendChallengeError(CE_ACCOUNT_CLOSED); return; case BAN_STATUS_TIME_LEFT_ON_BAN: SendChallengeError(CE_ACCOUNT_FREEZED); return; } // Null-terminate the account string m_challenge.I[m_challenge.I_len] = 0; // Look up the account information string AccountName = (char*)&m_challenge.I; sLog.outDebug("[AuthChallenge] Account Name: \"%s\"", AccountName.c_str()); m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { sLog.outDebug("[AuthChallenge] Invalid account."); // Non-existant account SendChallengeError(CE_NO_ACCOUNT); return; } sLog.outDebug("[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; } 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); }