Exemple #1
0
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));
}
Exemple #2
0
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);
}
Exemple #3
0
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);
}
Exemple #4
0
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()));
	}
}
Exemple #5
0
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");
}
Exemple #6
0
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);
}
Exemple #7
0
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);
}
Exemple #8
0
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);
}
Exemple #9
0
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;



}
Exemple #10
0
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 ) );
}
Exemple #11
0
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);
}
Exemple #12
0
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);
}