示例#1
0
void VoiceChatClientSocket::OnRead()
{
	WorldPacket *data;

	// uint16 op
	// uint16 size
	// <data>

	for(;;)
	{
		// no more data
		if( GetReadBuffer().GetSize() < 4 )
			break;

		GetReadBuffer().Read((uint8*)&op, 2);
		GetReadBuffer().Read((uint8*)&remaining, 2);

		if( GetReadBuffer().GetSize() < remaining )
			break;

		data = new WorldPacket(op, remaining);
		data->resize(remaining);
		GetReadBuffer().Read((uint8*)data->contents(), remaining);

		// handle the packet
		sVoiceChatHandler.OnRead(data);

		delete data;
		remaining = op = 0;
	}
}
void AuthSocket::HandleReconnectProof()
{
	if( m_account == NULL )
		return;

	// Load sessionkey from account database.
	QueryResult * result = sLogonSQL->Query ("SELECT SessionKey FROM accounts WHERE acct = %u", m_account->AccountId);
	if(result)
	{
		Field * field = result->Fetch();
		K.SetHexStr(field[0].GetString ());
		delete result;
	}
	else
	{
	    // Disconnect if the sessionkey invalid or not found
		DEBUG_LOG("AuthReConnectProof","No matching SessionKey found while user %s tried to login.", AccountName.c_str());
		Disconnect();
		return;
	}

	if(GetReadBuffer().GetSize() < sizeof(sAuthLogonProofKey_C))
		return;

	sAuthLogonProofKey_C lp;
	GetReadBuffer().Read(&lp, sizeof(sAuthLogonProofKey_C));

	BigNumber A;
	A.SetBinary(lp.R1, 16);

	Sha1Hash sha;
	sha.Initialize();
	sha.UpdateData(AccountName);
	sha.UpdateBigNumbers(&A, &rs, &K, 0);
	sha.Finalize();

	if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH))
	{
		///- Sending response
		ByteBuffer pkt;
		pkt << (uint8)  0x03;	//ReconnectProof
		pkt << (uint8)  0x00;
		pkt << (uint16) 0x00;	// 2 bytes zeros
		Send(pkt.contents(), pkt.size());

		// we're authenticated now :)
		m_authenticated = true;

		DEBUG_LOG("AuthReConnectProof","Authentication Success.");
	}
	else
		DEBUG_LOG("AuthReConnectProof","Authentication Failed.");

}
示例#3
0
void AuthSocket::OnRecvData()
{
	if(GetReadBuffer()->GetSize() < 1)
		return;

	uint8 Command = *(uint8*)GetReadBuffer()->GetBufferOffset();
	last_recv = UNIXTIME;
	if(Command < MAX_AUTH_CMD && Handlers[Command] != NULL)
		(this->*Handlers[Command])();
	else
		Log.Notice("AuthSocket", "Unknown cmd %u", Command);
}
示例#4
0
void AuthSocket::OnRead()
{
	if(GetReadBuffer().GetContiguiousBytes() < 1)
		return;

	uint8 Command = *(uint8*)GetReadBuffer().GetBufferStart();
	last_recv = UNIXTIME;
	if(Command < MAX_AUTH_CMD && Handlers[Command] != NULL)
		(this->*Handlers[Command])();
	else
		Log.Debug("AuthSocket", "Unknown cmd %u", Command);
}
示例#5
0
void Battlenet::Session::ReadHandler()
{
    BitStream stream(std::move(GetReadBuffer()));
    _crypt.DecryptRecv(stream.GetBuffer(), stream.GetSize());

    while (!stream.IsRead())
    {
        try
        {
            PacketHeader header;
            header.Opcode = stream.Read<uint32>(6);
            if (stream.Read<bool>(1))
                header.Channel = stream.Read<int32>(4);

            if (header.Channel != AUTHENTICATION && (header.Channel != CONNECTION || header.Opcode != Connection::CMSG_PING) && !_authed)
            {
                TC_LOG_DEBUG("session.packets", "%s Received not allowed %s. Client has not authed yet.", GetClientInfo().c_str(), header.ToString().c_str());
                CloseSocket();
                return;
            }

            if (ClientPacket* packet = sPacketManager.CreateClientPacket(header, stream))
            {
                if (sPacketManager.IsHandled(header))
                    TC_LOG_DEBUG("session.packets", "%s Received %s", GetClientInfo().c_str(), PacketToStringHelper(packet).c_str());

                packet->CallHandler(this);
                delete packet;
            }
            else if (sPacketManager.GetClientPacketName(header))
            {
                LogUnhandledPacket(header);
                break;
            }
            else
            {
                TC_LOG_DEBUG("session.packets", "%s Received unknown %s", GetClientInfo().c_str(), header.ToString().c_str());
                break;
            }

            stream.AlignToNextByte();
        }
        catch (BitStreamPositionException const& e)
        {
            TC_LOG_ERROR("session.packets", "%s Exception thrown during packet processing %s", GetClientInfo().c_str(), e.what());
            CloseSocket();
            return;
        }
    }

    GetReadBuffer().Resize(size_t(BufferSizes::Read));
    AsyncRead();
}
示例#6
0
void AuthSocket::HandleTransferResume()
{
	DEBUG_LOG("AuthSocket","Resuming transfer");
	if(!m_patch)
		return;

	GetReadBuffer()->Remove(1);
	uint64 size;
	GetReadBuffer()->Read(&size, 8);
	if(size>=m_patch->FileSize)
		return;

	PatchMgr::getSingleton().BeginPatchJob(m_patch,this,(uint32)size);
}
示例#7
0
void AuthSocket::HandleTransferResume()
{
	sLog.outDebug("Resuming transfer");
	if(!m_patch)
		return;

	//RemoveReadBufferBytes(1,false);
	GetReadBuffer().Remove(1);
	uint64 size;
	//Read(8,(uint8*)&size);
	GetReadBuffer().Read(&size, 8);
	if(size>=m_patch->FileSize)
		return;

	PatchMgr::getSingleton().BeginPatchJob(m_patch,this,(uint32)size);
}
示例#8
0
void AuthSocket::HandleReconnectProof()
{
	/*
	printf("Len: %u\n", this->GetReadBufferSize());
	ByteBuffer buf(58);
	buf.resize(58);
	Read(58, const_cast<uint8*>(buf.contents()));
	buf.hexlike();*/

	if (!m_account)
		return;

	// 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);
	//RemoveReadBufferBytes(GetReadBufferSize(), true);
	GetReadBuffer().Remove(GetWriteBuffer().GetSize());

	if(!m_account->SessionKey)
	{
		uint8 buffer[4];
		buffer[0] = 3;
		buffer[1] = 0;
		buffer[2] = 1;
		buffer[3] = 0;
		Send(buffer, 4);
	}
	else
	{
		uint32 x = 3;
		Send((const uint8*)&x, 4);
	}
}
示例#9
0
void AuthSocket::OnRead()
{
	if(GetReadBufferSize() < 1)
		return;

	uint8 Command = GetReadBuffer(0)[0];

	// Handle depending on command
	switch(Command)
	{
	case 0:	 // AUTH_CHALLENGE
		last_recv = time(NULL);
		HandleChallenge();
		break;

	case 1:	 // AUTH_PROOF
		last_recv = time(NULL);
		HandleProof();
		break;

	case 0x10:  // REALM_LIST
		last_recv = time(NULL);
		HandleRealmlist();
		break;
	}
}
示例#10
0
void LogonCommServerSocket::OnRecvData()
{
	while(true)
	{
		if(!remaining)
		{
			if(GetReadBuffer()->GetSize() < 6)
				return;	 // no header

			// read header
			Read((uint8*)&opcode, 2);
			Read((uint8*)&remaining, 4);

			if(use_crypto)
			{
				// decrypt the packet
				recvCrypto.Process((unsigned char*)&opcode, (unsigned char*)&opcode, 2);
				recvCrypto.Process((unsigned char*)&remaining, (unsigned char*)&remaining, 4);
			}

			EndianConvert(opcode);
			/* reverse byte order */
			EndianConvertReverse(remaining);
		}

		// do we have a full packet?
		if(GetReadBuffer()->GetSize() < remaining)
			return;

		// create the buffer
		WorldPacket buff(opcode, remaining);
		if(remaining)
		{
			buff.resize(remaining);
			Read((uint8*)buff.contents(), remaining);
		}

		if(use_crypto && remaining)
			recvCrypto.Process((unsigned char*)buff.contents(), (unsigned char*)buff.contents(), remaining);

		// handle the packet
		HandlePacket(buff);

		remaining = 0;
		opcode = 0;
	}
}
示例#11
0
void AuthSocket::HandleTransferAccept()
{
	DEBUG_LOG("AuthSocket","Accepted transfer");
	if(!m_patch)
		return;

	GetReadBuffer()->Remove(1);
	PatchMgr::getSingleton().BeginPatchJob(m_patch,this,0);
}
示例#12
0
void AuthSocket::HandleTransferAccept()
{
	sLog.outDebug("Accepted transfer");
	if(!m_patch)
		return;

	//RemoveReadBufferBytes(1,false);
	GetReadBuffer().Remove(1);
	PatchMgr::getSingleton().BeginPatchJob(m_patch,this,0);
}
示例#13
0
void Socket::ReadHandler()
{
    if (!IsOpen())
        return;

    MessageBuffer& packet = GetReadBuffer();
    while (packet.GetActiveSize() > 0)
    {
        if (_headerBuffer.GetRemainingSpace() > 0)
        {
            // need to receive the header
            std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
            _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
            packet.ReadCompleted(readHeaderSize);

            if (_headerBuffer.GetRemainingSpace() > 0)
                break;

            // We just received nice new header
            if (!ReadHeaderHandler())
            {
                CloseSocket();
                return;
            }
        }

        // We have full read header, now check the data payload
        if (_packetBuffer.GetRemainingSpace() > 0)
        {
            // need more data in the payload
            std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
            _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
            packet.ReadCompleted(readDataSize);

            if (_packetBuffer.GetRemainingSpace() > 0)
            {
                // Couldn't receive the whole data this time.
                break;
            }
        }
        // just received fresh new payload
        if (!ReadDataHandler())
        {
            CloseSocket();
            _headerBuffer.Reset();
            return;
        }

        _headerBuffer.Reset();
    }

    AsyncRead();
}
示例#14
0
void AuthSocket::OnRead()
{
	if(GetReadBufferSize() < 1)
		return;

	uint8 Command = GetReadBuffer(0)[0];
	last_recv = UNIXTIME;
	if(Command < MAX_AUTH_CMD && Handlers[Command] != NULL)
		(this->*Handlers[Command])();
	else
		Log.Notice("AuthSocket", "Unknown cmd %u", Command);
}
示例#15
0
void Battlenet::Session::ReadHandler()
{
    if (!IsOpen())
        return;

    MessageBuffer& packet = GetReadBuffer();
    while (packet.GetActiveSize() > 0)
    {
        if (!PartialProcessPacket<&Battlenet::Session::ReadHeaderLengthHandler, &Battlenet::Session::_headerLengthBuffer>(this, packet))
            break;

        if (!PartialProcessPacket<&Battlenet::Session::ReadHeaderHandler, &Battlenet::Session::_headerBuffer>(this, packet))
            break;

        if (!PartialProcessPacket<&Battlenet::Session::ReadDataHandler, &Battlenet::Session::_packetBuffer>(this, packet))
            break;

        _headerLengthBuffer.Reset();
        _headerBuffer.Reset();
    }

    AsyncRead();
}
示例#16
0
void AuthSocket::HandleTransferCancel()
{
	//RemoveReadBufferBytes(1,false);
	GetReadBuffer().Remove(1);
	Disconnect();
}
示例#17
0
void WSClient::OnRecvData()
{
	for(;;)
	{
		if(!_cmd)
		{
			if(GetReadBuffer()->GetSize() < 6)
				break;

			Read((uint8*)&_cmd, 2);
			Read((uint8*)&_remaining, 4);
		}

		if(_remaining && GetReadBuffer()->GetSize() < _remaining)
			return;

		if(_cmd == SMSGR_WOW_PACKET)
		{
			uint32 sid = 0;
			uint16 op = 0;
			uint32 sz = 0;
			Read(&sid, 4);
			Read(&op, 2);
			Read(&sz, 4);

			WorldSession * session = sClusterInterface.GetSession(sid);
			if(session != NULL)
			{
				WorldPacket * pck = new WorldPacket(op, sz);
				if (sz > 0)
				{
					pck->resize(sz);
					Read((void*)pck->contents(), sz);
				}

				if(session)
					session->QueuePacket(pck);
				else
					delete pck;
			}
			_cmd = 0;
			continue;
		}

		WorldPacket * pck = new WorldPacket(_cmd, _remaining);
		_cmd = 0;
		if(_remaining)
		{
			pck->resize(_remaining);
			Read((uint8*)pck->contents(), _remaining);
		}

		/* we could handle auth here */
		switch(_cmd)
		{
		case SMSGR_AUTH_REQUEST:
			sClusterInterface.HandleAuthRequest(*pck);
			delete pck;
			break;
		default:
			sClusterInterface.QueuePacket(pck);
		}
	}
}
示例#18
0
void WorldSocket::OnRead()
{
	for(;;)
	{
		// Check for the header if we don't have any bytes to wait for.
		if(mRemaining == 0)
		{
			if(GetReadBuffer().GetSize() < 6)
			{
				// No header in the packet, let's wait.
				return;
			}

			// Copy from packet buffer into header local var
			ClientPktHeader Header;
			GetReadBuffer().Read(&Header, 6);

			// Decrypt the header
            _crypt.DecryptSixRecv((uint8*)&Header);

			mRemaining = mSize = ntohs(Header.size) - 4;
			mOpcode = Header.cmd;
		}

		WorldPacket * Packet;

		if(mRemaining > 0)
		{
			if( GetReadBuffer().GetSize() < mRemaining )
			{
				// We have a fragmented packet. Wait for the complete one before proceeding.
				return;
			}
		}

		Packet = new WorldPacket(mOpcode, mSize);
		Packet->resize(mSize);

		if(mRemaining > 0)
		{
			// Copy from packet buffer into our actual buffer.
			//Read(mRemaining, (uint8*)Packet->contents());
			GetReadBuffer().Read((uint8*)Packet->contents(), mRemaining);
		}

		/*sWorldLog.LogPacket(mSize, mOpcode, mSize ? Packet->contents() : NULL, 0);*/
		mRemaining = mSize = mOpcode = 0;

		// Check for packets that we handle
		switch(Packet->GetOpcode())
		{
		case CMSG_PING:
			{
				if(!m_session->m_currentPlayer)
				{
					_HandlePing(Packet);
					delete Packet;
				}
				else
					m_session->m_readQueue.Push(Packet);				
			}break;
		case CMSG_AUTH_SESSION:
			{
				_HandleAuthSession(Packet);
			}break;
		default:
			{
				if(m_session) m_session->m_readQueue.Push(Packet);
				else delete Packet;
			}break;
		}
	}
}
示例#19
0
void WorldSocket::OnRecvData()
{
	for(;;)
	{
		// Check for the header if we don't have any bytes to wait for.
		if(mRemaining == 0)
		{
			if(GetReadBuffer()->GetSize() < 6)
			{
				// No header in the packet, let's wait.
				return;
			}

			// Copy from packet buffer into header local var
			ClientPktHeader Header;
			Read(&Header, 6);

			// Decrypt the header
			_crypt.DecryptRecv((uint8*)&Header, sizeof (ClientPktHeader));
			mRemaining = mSize = ntohs(Header.size) - 4;
			mOpcode = Header.cmd;
		}

		if(mRemaining > 0)
		{
			if( GetReadBuffer()->GetSize() < mRemaining )
			{
				// We have a fragmented packet. Wait for the complete one before proceeding.
				return;
			}
		}

		WorldPacket *Packet = new WorldPacket(mOpcode, mSize);
		if(mRemaining > 0)
		{
			Packet->resize(mRemaining);
			Read((uint8*)Packet->contents(), mRemaining);

			if(!bServerShutdown)
				sWorld.NetworkStressIn += float(float(mSize+6)/1024);
		}
		mRemaining = mSize = mOpcode = 0;

		// Check for packets that we handle
		switch(Packet->GetOpcode())
		{
		case CMSG_PING:
			{
				_HandlePing(Packet);
				delete Packet;
			}break;
		case CMSG_AUTH_SESSION:
			{
				_HandleAuthSession(Packet);
			}break;
		default:
			{
				if(mSession)
					mSession->QueuePacket(Packet);
				else
				{
					delete Packet;
					Packet = NULL;
				}
			}break;
		}
	}
}
void ConsoleSocket::OnRecvData()
{
    uint32 readlen = (uint32)GetReadBuffer()->GetSize();
    uint32 rlen;
    char * p;
    if( ( readlen + m_pBufferPos ) >= m_pBufferLen )
    {
        Disconnect();
        return;
    }

    Read((uint8*)&m_pBuffer[m_pBufferPos], readlen);
    m_pBufferPos += readlen;

    // let's look for any newline bytes.
    p = strchr(m_pBuffer, '\n');
    while( p != NULL )
    {
        // windows is stupid. :P
        rlen = (uint32)((p+1) - m_pBuffer);
        if( *(p-1) == '\r' )
            *(p-1) = '\0';

        *p = '\0';

        // handle the command
        if( *m_pBuffer != '\0' )
        {
            switch(m_state)
            {
            case STATE_USER:
                m_username = string(m_pBuffer);
                m_pConsole->Write("password: "******"\r\nAttempting to authenticate. Please wait.\r\n");
                m_state = STATE_WAITING;

                m_requestNo = ConsoleAuthMgr::getSingleton().GenerateRequestId();
                ConsoleAuthMgr::getSingleton().SetRequest(m_requestNo, this);

                TestConsoleLogin(m_username, m_password, m_requestNo);
                break;

            case STATE_LOGGED:
                if( !strnicmp( m_pBuffer, "quit", 4 ) )
                {
                    Disconnect();
                    break;
                }

                HandleConsoleInput(m_pConsole, m_pBuffer);
                break;
            }
        }

        // move the bytes back
        if( rlen == m_pBufferPos )
        {
            m_pBuffer[0] = '\0';
            m_pBufferPos = 0;
        }
        else
        {
            memcpy(m_pBuffer, &m_pBuffer[rlen], m_pBufferPos - rlen);
            m_pBufferPos -= rlen;
        }

        p = strchr(m_pBuffer, '\n');
    }
}
示例#21
0
void AuthSocket::HandleTransferCancel()
{
	GetReadBuffer()->Remove(1);
	Disconnect();
}
示例#22
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");
}
示例#23
0
void WSSocket::OnRead()
{
    for(;;)
	{
		if(!_cmd)
		{
			if(readBuffer.GetSize() < 6)
				break;

			readBuffer.Read(&_cmd, 2);
			readBuffer.Read(&_remaining, 4);
		}

        if(_remaining && readBuffer.GetSize() < _remaining)
			break;

		if(_cmd == ICMSG_WOW_PACKET)
		{
			uint32 sid;
			uint16 op;
			uint32 sz;


			GetReadBuffer().Read(&sid, 4);
			GetReadBuffer().Read(&op, 2);
			GetReadBuffer().Read(&sz, 4);

			Session * session = sClientMgr.GetSession(sid);
			if(session != NULL && session->GetSocket() != NULL)
			{
				uint8* buf = new uint8[sz];
				GetReadBuffer().Read(buf, sz);
				session->GetSocket()->OutPacket(op, sz, buf);
				delete [] buf;
			}
			else
				GetReadBuffer().Remove(sz);

			_cmd = 0;

			continue;
		}
		WorldPacket * pck = new WorldPacket(_cmd, _remaining);
		_cmd = 0;
		pck->resize(_remaining);
		readBuffer.Read((uint8*)pck->contents(), _remaining);

		if(_authenticated)
		{
			// push to queue
			if(!_ws)
			{
				if(pck->GetOpcode() == ICMSG_REGISTER_WORKER)
				{
					// handle register worker
					HandleRegisterWorker(*pck);
				}

				/* I deliberately don't delete pck here for a reason :P */
			}
			else
			{
				_ws->QueuePacket(pck);
			}
		}
		else
		{
			if(pck->GetOpcode() != ICMSG_AUTH_REPLY)
				Disconnect();
			else
				HandleAuthRequest(*pck);
			
			delete pck;
		}
	}
}
示例#24
0
void KOSocket::OnRead()
{
    Packet pkt;

    for (;;)
    {
        if (m_remaining == 0)
        {
            if (GetReadBuffer().GetSize() < 5)
                return; //check for opcode as well

            uint16 header = 0;
            GetReadBuffer().Read(&header, 2);
            if (header != 0x55aa)
            {
                TRACE("%s: Got packet without header 0x55AA, got 0x%X\n", GetRemoteIP().c_str(), header);
                goto error_handler;
            }

            GetReadBuffer().Read(&m_remaining, 2);
            if (m_remaining == 0)
            {
                TRACE("%s: Got packet without an opcode, this should never happen.\n", GetRemoteIP().c_str());
                goto error_handler;
            }
        }

        if (m_remaining > GetReadBuffer().GetAllocatedSize())
        {
            TRACE("%s: Packet received which was %u bytes in size, maximum of %u.\n", GetRemoteIP().c_str(), m_remaining, GetReadBuffer().GetAllocatedSize());
            goto error_handler;
        }

        if (m_remaining > GetReadBuffer().GetSize())
        {
            if (m_readTries > 4)
            {
                TRACE("%s: packet fragmentation count is over 4, disconnecting as they're probably up to something bad\n", GetRemoteIP().c_str());
                goto error_handler;
            }
            m_readTries++;
            return;
        }

        uint8 *in_stream = new uint8[m_remaining];

        m_readTries = 0;
        GetReadBuffer().Read(in_stream, m_remaining);

        uint16 footer = 0;
        GetReadBuffer().Read(&footer, 2);

        if (footer != 0xaa55
                || !DecryptPacket(in_stream, pkt))
        {
            TRACE("%s: Footer invalid (%X) or failed to decrypt.\n", GetRemoteIP().c_str(), footer);
            delete [] in_stream;
            goto error_handler;
        }

        delete [] in_stream;

        if (!HandlePacket(pkt))
        {

            TRACE("%s: Handler for packet %X returned false\n", GetRemoteIP().c_str(), pkt.GetOpcode());
#ifndef _DEBUG
            goto error_handler;
#endif
        }

        m_remaining = 0;
    }

    return;

error_handler:
    GetReadBuffer().Remove(GetReadBuffer().GetSize());
    Disconnect();
}
示例#25
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()));
	}
}
示例#26
0
void AuthSocket::HandleReconnectChallenge()
{
	// No header
	if(GetReadBuffer().GetContiguiousBytes() < 4)
		return;	

	// Check the rest of the packet is complete.
	uint8 * ReceiveBuffer = /*GetReadBuffer(0)*/(uint8*)GetReadBuffer().GetBufferStart();
	uint16 full_size = *(uint16*)&ReceiveBuffer[2];
	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((size_t)(full_size+4) > sizeof(sAuthLogonChallenge_C))
	{
		Disconnect();
		return;
	}

	sLog.outDebug("[AuthChallenge] got full packet.");

	memcpy(&m_challenge, ReceiveBuffer, full_size + 4);
	//RemoveReadBufferBytes(full_size + 4, false);
	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
	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;
	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;
	}

	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);
}
示例#27
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);
}
示例#28
0
void WorldSocket::OnRead()
{
	for(;;)
	{
		// Check for the header if we don't have any bytes to wait for.
		if(mRemaining == 0)
		{
			if(GetReadBuffer().GetSize() < 6)
			{
				// No header in the packet, let's wait.
				return;
			}

			// Copy from packet buffer into header local var
			ClientPktHeader Header;
			GetReadBuffer().Read((uint8*)&Header, 6);

			// Decrypt the header
			_crypt.DecryptRecv((uint8*)&Header, sizeof (ClientPktHeader));
#ifdef USING_BIG_ENDIAN
			mRemaining = mSize = Header.size - 4;
			mOpcode = swap32(Header.cmd);
#else
			mRemaining = mSize = ntohs(Header.size) - 4;
			mOpcode = Header.cmd;
#endif
		}

		WorldPacket * Packet;

		if(mRemaining > 0)
		{
			if( GetReadBuffer().GetSize() < mRemaining )
			{
				// We have a fragmented packet. Wait for the complete one before proceeding.
				return;
			}
		}

		Packet = new WorldPacket( static_cast<uint16>( mOpcode ), mSize);
		Packet->resize(mSize);

		if(mRemaining > 0)
		{
			// Copy from packet buffer into our actual buffer.
			///Read(mRemaining, (uint8*)Packet->contents());
			GetReadBuffer().Read((uint8*)Packet->contents(), mRemaining);
		}

		sWorldLog.LogPacket(mSize, static_cast<uint16>( mOpcode ), mSize ? Packet->contents() : NULL, 0, (mSession ? mSession->GetAccountId() : 0) );
		mRemaining = mSize = mOpcode = 0;

		// Check for packets that we handle
		switch(Packet->GetOpcode())
		{
		case CMSG_PING:
			{
				_HandlePing(Packet);
				delete Packet;
			}break;
		case CMSG_AUTH_SESSION:
			{
				_HandleAuthSession(Packet);
			}break;
		default:
			{
				if(mSession) mSession->QueuePacket(Packet);
				else delete Packet;
			}break;
		}
	}
}
示例#29
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);
}