Exemplo n.º 1
0
/// Make the SRP6 calculation from hash in dB
void AuthSocket::_SetVSFields(const std::string& rI)
{
    s.SetRand(s_BYTE_SIZE * 8);

    BigNumber I;
    I.SetHexStr(rI.c_str());

    // In case of leading zeros in the rI hash, restore them
    uint8 mDigest[SHA_DIGEST_LENGTH];
    memset(mDigest, 0, SHA_DIGEST_LENGTH);
    if (I.GetNumBytes() <= SHA_DIGEST_LENGTH)
        memcpy(mDigest, I.AsByteArray(), I.GetNumBytes());

    std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH);

    Sha1Hash sha;
    sha.UpdateData(s.AsByteArray(), s.GetNumBytes());
    sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
    sha.Finalize();
    BigNumber x;
    x.SetBinary(sha.GetDigest(), sha.GetLength());
    v = g.ModExp(x, N);
    // No SQL injection (username escaped)
    const char *v_hex, *s_hex;
    v_hex = v.AsHexStr();
    s_hex = s.AsHexStr();
    LoginDatabase.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '******'", v_hex, s_hex, _safelogin.c_str() );
    OPENSSL_free((void*)v_hex);
    OPENSSL_free((void*)s_hex);
}
Exemplo n.º 2
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.");

}
Exemplo n.º 3
0
void Battlenet::Session::_SetVSFields(std::string const& pstr)
{
    s.SetRand(uint32(BufferSizes::SRP_6_S) * 8);

    BigNumber p;
    p.SetHexStr(pstr.c_str());

    SHA256Hash sha;
    sha.UpdateBigNumbers(&s, &p, NULL);
    sha.Finalize();
    BigNumber x;
    x.SetBinary(sha.GetDigest(), sha.GetLength());
    v = g.ModExp(x, N);

    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS);
    stmt->setString(0, v.AsHexStr());
    stmt->setString(1, s.AsHexStr());
    stmt->setString(2, _accountInfo->Login);

    LoginDatabase.Execute(stmt);
}
Exemplo n.º 4
0
// Make the SRP6 calculation from hash in dB
void AuthSocket::_SetVSFields(const std::string& rI)
{
    s.SetRand(s_BYTE_SIZE * 8);

    BigNumber I;
    I.SetHexStr(rI.c_str());

    // In case of leading zeros in the rI hash, restore them
    uint8 mDigest[SHA_DIGEST_LENGTH];
    memset(mDigest, 0, SHA_DIGEST_LENGTH);
    if (I.GetNumBytes() <= SHA_DIGEST_LENGTH)
	{
        memcpy(mDigest, I.AsByteArray(), I.GetNumBytes());
	}

    std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH);

    SHA1Hash sha;
    sha.UpdateData(s.AsByteArray(), s.GetNumBytes());
    sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
    sha.Finalize();
    BigNumber x;
    x.SetBinary(sha.GetDigest(), sha.GetLength());
    v = g.ModExp(x, N);

    // No SQL injection (username escaped)
    const char *v_hex, *s_hex;
    v_hex = v.AsHexStr();
    s_hex = s.AsHexStr();

    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS);
    stmt->setString(0, v_hex);
    stmt->setString(1, s_hex);
    stmt->setString(2, _login);
    LoginDatabase.Execute(stmt);

    OPENSSL_free((void*)v_hex);
    OPENSSL_free((void*)s_hex);
}
Exemplo n.º 5
0
/// Make the SRP6 calculation from hash in dB
void AuthSocket::_SetVSFields(std::string rI)
{
    BigNumber I;
    I.SetHexStr(rI.c_str());

    //In case of leading zeroes in the rI hash, restore them
    uint8 mDigest[SHA_DIGEST_LENGTH];
    memset(mDigest,0,SHA_DIGEST_LENGTH);
    if (I.GetNumBytes() <= SHA_DIGEST_LENGTH)
        memcpy(mDigest,I.AsByteArray(),I.GetNumBytes());

    std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH);

    Sha1Hash sha;
    sha.UpdateData(s.AsByteArray(), s.GetNumBytes());
    sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
    sha.Finalize();
    BigNumber x;
    x.SetBinary(sha.GetDigest(), sha.GetLength());
    v = g.ModExp(x, N);
    // No SQL injection (username escaped)
    dbRealmServer.PExecute("UPDATE `account` SET `v` = '%s', `s` = '%s' WHERE UPPER(`username`)= UPPER('%s')",v.AsHexStr(),s.AsHexStr(), _safelogin.c_str() );
}
Exemplo n.º 6
0
void WorldSocket::InformationRetreiveCallback(WorldPacket & recvData, uint32 requestid)
{
	if(requestid != mRequestID)
		return;

	uint32 error;
	recvData >> error;

	if(error != 0)
	{
		// something happened wrong @ the logon server
		OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
		return;
	}

	// Extract account information from the packet.
	string AccountName;
	uint32 AccountID;
	string GMFlags;
	uint32 AccountFlags;

	recvData >> AccountID >> AccountName >> GMFlags >> AccountFlags;
	sLog.outDebug( " >> got information packet from logon: `%s` ID %u (request %u)", AccountName.c_str(), AccountID, mRequestID);
	//	sLog.outColor(TNORMAL, "\n");

	mRequestID = 0;
	// Pull the session key.
	uint8 K[40];
	recvData.read(K, 40);

	BigNumber BNK;
	BNK.SetBinary(K, 40);

	// Initialize crypto.
	_crypt.SetKey(K, 40);
	_crypt.Init();

	Session * session = sClientMgr.CreateSession(AccountID);
	if(session == NULL)
	{
		/* we are already logged in. send auth failed. (if anyone has a better error lemme know :P) */
		OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
		return;
	}

	m_session = session;
	session->m_socket = this;
    Sha1Hash sha;

	uint8 digest[20];
	pAuthenticationPacket->read(digest, 20);

	uint32 t = 0;
	sha.UpdateData(AccountName);
	sha.UpdateData((uint8 *)&t, 4);
	sha.UpdateData((uint8 *)&mClientSeed, 4);
	sha.UpdateData((uint8 *)&mSeed, 4);
	sha.UpdateBigNumbers(&BNK, NULL);
	sha.Finalize();

	if (memcmp(sha.GetDigest(), digest, 20))
	{
		// AUTH_UNKNOWN_ACCOUNT = 21
		OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15");
		return;
	}

	// Allocate session
	m_session->m_accountFlags = AccountFlags;
	m_session->m_GMPermissions = GMFlags;
	m_session->m_accountId = AccountID;
	m_session->m_latency = _latency;
	m_session->m_accountName = AccountName;

	Log.Notice("Auth", "%s from %s:%u [%ums]", AccountName.c_str(), GetRemoteIP().c_str(), GetRemotePort(), _latency);
	Authenticate();
}
Exemplo n.º 7
0
// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
    sLog->outDebug(LOG_FILTER_AUTHSERVER, "Entering _HandleLogonProof");
    // Read the packet
    sAuthLogonProof_C lp;

    if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C)))
        return false;

    // Continue the SRP6 calculation based on data received from the client
    BigNumber A;

    A.SetBinary(lp.A, 32);

    // SRP safeguard: abort if A == 0
    if (A.isZero())
    {
        socket().shutdown();
        return true;
    }

    SHA1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(32), 32);

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2] = sha.GetDigest()[i];

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2 + 1];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2 + 1] = sha.GetDigest()[i];

    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        hash[i] ^= sha.GetDigest()[i];

    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, NULL);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    // Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(), lp.M1, 20))
    {
        sLog->outDebug(LOG_FILTER_AUTHSERVER, "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());

        // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        const char *K_hex = K.AsHexStr();

        PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
        stmt->setString(0, K_hex);
        stmt->setString(1, socket().getRemoteAddress().c_str());
        stmt->setUInt32(2, GetLocaleByName(_localizationName));
        stmt->setString(3, _os);
        stmt->setString(4, _login);
        LoginDatabase.Execute(stmt);

        QueryResult AccountIdResult = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '******'", _login.c_str());

        if (AccountIdResult)
        {
            uint32 accountid = (AccountIdResult->Fetch())[0].GetUInt32();

            stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG_IP);
            stmt->setUInt32(0, accountid);
            stmt->setString(1, socket().getRemoteAddress().c_str());
            LoginDatabase.Execute(stmt);
        }

        OPENSSL_free((void*)K_hex);

        // Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        // Check auth token
        if ((lp.securityFlags & 0x04) || !_tokenKey.empty())
        {
            uint8 size;
            socket().recv((char*)&size, 1);
            char* token = new char[size + 1];
            token[size] = '\0';
            socket().recv(token, size);
            unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str());
            unsigned int incomingToken = atoi(token);
            delete[] token;
            if (validToken != incomingToken)
            {
                char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 };
                socket().send(data, sizeof(data));
                return false;
            }
        }

        sAuthLogonProof_S proof;
        memcpy(proof.M2, sha.GetDigest(), 20);
        proof.cmd = AUTH_LOGON_PROOF;
        proof.error = 0;
        proof.unk1 = 0x00800000;    // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
        proof.unk2 = 0x00;          // SurveyId
        proof.unk3 = 0x00;
        socket().send((char *)&proof, sizeof(proof));

        _authed = true;
    }
    else
    {
        char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 };
        socket().send(data, sizeof(data));

        sLog->outDebug(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ());

        uint32 MaxWrongPassCount = ConfigMgr::GetIntDefault("WrongPass.MaxCount", 0);
        if (MaxWrongPassCount > 0)
        {
            //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS);
            stmt->setString(0, _login);
            LoginDatabase.Execute(stmt);

            stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS);
            stmt->setString(0, _login);

            if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt))
            {
                uint32 failed_logins = (*loginfail)[1].GetUInt32();

                if (failed_logins >= MaxWrongPassCount)
                {
                    uint32 WrongPassBanTime = ConfigMgr::GetIntDefault("WrongPass.BanTime", 600);
                    bool WrongPassBanType = ConfigMgr::GetBoolDefault("WrongPass.BanType", false);

                    if (WrongPassBanType)
                    {
                        uint32 acc_id = (*loginfail)[0].GetUInt32();
                        stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED);
                        stmt->setUInt32(0, acc_id);
                        stmt->setUInt32(1, WrongPassBanTime);
                        LoginDatabase.Execute(stmt);

                        sLog->outDebug(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                            socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins);
                    }
                    else
                    {
                        stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED);
                        stmt->setString(0, socket().getRemoteAddress());
                        stmt->setUInt32(1, WrongPassBanTime);
                        LoginDatabase.Execute(stmt);

                        sLog->outDebug(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times",
                            socket().getRemoteAddress().c_str(), socket().getRemotePort(), socket().getRemoteAddress().c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
                    }
                }
            }
        }
    }

    return true;
}
Exemplo n.º 8
0
// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
    sLog->outStaticDebug("Entering _HandleLogonProof");
    // Read the packet
    sAuthLogonProof_C lp;

    if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C)))
        return false;

    // If the client has no valid version
    if (_expversion == NO_VALID_EXP_FLAG)
    {
        // Check if we have the appropriate patch on the disk
        sLog->outDebug(LOG_FILTER_NETWORKIO, "Client with invalid version, patching is not implemented");
        socket().shutdown();
        return true;
    }

    // Continue the SRP6 calculation based on data received from the client
    BigNumber A;

    A.SetBinary(lp.A, 32);

    // SRP safeguard: abort if A == 0
    if (A.isZero())
    {
        socket().shutdown();
        return true;
    }

    SHA1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(32), 32);

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2] = sha.GetDigest()[i];

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2 + 1];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2 + 1] = sha.GetDigest()[i];

    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        hash[i] ^= sha.GetDigest()[i];

    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, NULL);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    // Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(), lp.M1, 20))
    {
        sLog->outBasic("User '%s' successfully authenticated", _login.c_str());

        // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        const char *K_hex = K.AsHexStr();

        PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SET_LOGONPROOF);
        stmt->setString(0, K_hex);
        stmt->setString(1, socket().get_remote_address().c_str());
        stmt->setUInt32(2, GetLocaleByName(_localizationName));
        stmt->setString(3, _os);
        stmt->setString(4, _login);
        LoginDatabase.Execute(stmt);

        OPENSSL_free((void*)K_hex);

        // Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        if (_expversion & POST_BC_EXP_FLAG)                 // 2.x and 3.x clients
        {
            sAuthLogonProof_S proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.unk1 = 0x00800000;    // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
            proof.unk2 = 0x00;          // SurveyId
            proof.unk3 = 0x00;
            socket().send((char *)&proof, sizeof(proof));
        }
        else
        {
            sAuthLogonProof_S_Old proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.unk2 = 0x00;
            socket().send((char *)&proof, sizeof(proof));
        }

        _authed = true;
    }
    else
    {
        char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 };
        socket().send(data, sizeof(data));

        sLog->outBasic("[AuthChallenge] account %s tried to login with wrong password!", _login.c_str());

        uint32 MaxWrongPassCount = ConfigMgr::GetIntDefault("WrongPass.MaxCount", 0);
        if (MaxWrongPassCount > 0)
        {
            //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SET_FAILEDLOGINS);
            stmt->setString(0, _login);
            LoginDatabase.Execute(stmt);

            stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_FAILEDLOGINS);
            stmt->setString(0, _login);

            if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt))
            {
                uint32 failed_logins = (*loginfail)[1].GetUInt32();

                if (failed_logins >= MaxWrongPassCount)
                {
                    uint32 WrongPassBanTime = ConfigMgr::GetIntDefault("WrongPass.BanTime", 600);
                    bool WrongPassBanType = ConfigMgr::GetBoolDefault("WrongPass.BanType", false);

                    if (WrongPassBanType)
                    {
                        uint32 acc_id = (*loginfail)[0].GetUInt32();
                        stmt = LoginDatabase.GetPreparedStatement(LOGIN_SET_ACCAUTOBANNED);
                        stmt->setUInt32(0, acc_id);
                        stmt->setUInt32(1, WrongPassBanTime);
                        LoginDatabase.Execute(stmt);

                        sLog->outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                            _login.c_str(), WrongPassBanTime, failed_logins);
                    }
                    else
                    {
                        stmt = LoginDatabase.GetPreparedStatement(LOGIN_SET_IPAUTOBANNED);
                        stmt->setString(0, socket().get_remote_address());
                        stmt->setUInt32(1, WrongPassBanTime);
                        LoginDatabase.Execute(stmt);

                        sLog->outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", socket().get_remote_address().c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
                    }
                }
            }
        }
    }

    return true;
}
Exemplo n.º 9
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);
}
Exemplo n.º 10
0
/// Logon Challenge command handler
bool AuthSocket::_HandleLogonChallenge()
{
    DEBUG_LOG("Entering _HandleLogonChallenge");
    if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C))
        return false;

    ///- Read the first 4 bytes (header) to get the length of the remaining of the packet
    std::vector<uint8> buf;
    buf.resize(4);

    ibuf.Read((char *)&buf[0], 4);

    EndianConvert(*((uint16*)(buf[0])));
    uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size;
    DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining);

    if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ibuf.GetLength() < remaining))
        return false;

    //No big fear of memory outage (size is int16, i.e. < 65536)
    buf.resize(remaining + buf.size() + 1);
    buf[buf.size() - 1] = 0;
    sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0];

    // BigEndian code, nop in little endian case
    // size already converted
    EndianConvert(*((uint32*)(&ch->gamename[0])));
    EndianConvert(ch->build);
    EndianConvert(*((uint32*)(&ch->platform[0])));
    EndianConvert(*((uint32*)(&ch->os[0])));
    EndianConvert(*((uint32*)(&ch->country[0])));
    EndianConvert(ch->timezone_bias);
    EndianConvert(ch->ip);

    ///- Read the remaining of the packet
    ibuf.Read((char *)&buf[4], remaining);
    DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size);
    DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I);

    ByteBuffer pkt;

    _login = (const char*)ch->I;
    _build = ch->build;

    ///- Normalize account name
    //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form

    //Escape the user login to avoid further SQL injection
    //Memory will be freed on AuthSocket object destruction
    _safelogin = _login;
    loginDatabase.escape_string(_safelogin);

    pkt << (uint8) AUTH_LOGON_CHALLENGE;
    pkt << (uint8) 0x00;

    ///- Verify that this IP is not in the ip_banned table
    // No SQL injection possible (paste the IP address as passed by the socket)
    loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");

    std::string address = GetRemoteAddress();
    loginDatabase.escape_string(address);
    QueryResult *result = loginDatabase.PQuery("SELECT * FROM ip_banned WHERE ip = '%s'",address.c_str());
    if(result)
    {
        pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED;
        sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!",GetRemoteAddress().c_str ());
        delete result;
    }
    else
    {
        ///- Get the account details from the account table
        // No SQL injection (escaped user name)

        result = loginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'",_safelogin.c_str ());
        if( result )
        {
            ///- If the IP is 'locked', check that the player comes indeed from the correct IP address
            bool locked = false;
            if((*result)[2].GetUInt8() == 1)                // if ip is locked
            {
                DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString());
                DEBUG_LOG("[AuthChallenge] Player address is '%s'", GetRemoteAddress().c_str());
                if ( strcmp((*result)[3].GetString(),GetRemoteAddress().c_str()) )
                {
                    DEBUG_LOG("[AuthChallenge] Account IP differs");
                    pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
                    locked=true;
                }
                else
                {
                    DEBUG_LOG("[AuthChallenge] Account IP matches");
                }
            }
            else
            {
                DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str());
            }

            if (!locked)
            {
                //set expired bans to inactive
                loginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
                ///- If the account is banned, reject the logon attempt
                QueryResult *banresult = loginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = %u AND active = 1", (*result)[1].GetUInt32());
                if(banresult)
                {
                    if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64())
                    {
                        pkt << (uint8) REALM_AUTH_ACCOUNT_BANNED;
                        sLog.outBasic("[AuthChallenge] Banned account %s tries to login!",_login.c_str ());
                    }
                    else
                    {
                        pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
                        sLog.outBasic("[AuthChallenge] Temporarily banned account %s tries to login!",_login.c_str ());
                    }

                    delete banresult;
                }
                else
                {
                    ///- Get the password from the account table, upper it, and make the SRP6 calculation
                    std::string rI = (*result)[0].GetCppString();

                    ///- Don't calculate (v, s) if there are already some in the database
                    std::string databaseV = (*result)[5].GetCppString();
                    std::string databaseS = (*result)[6].GetCppString();

                    sLog.outDebug("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str());

                    // multiply with 2, bytes are stored as hexstring
                    if(databaseV.size() != s_BYTE_SIZE*2 || databaseS.size() != s_BYTE_SIZE*2)
                        _SetVSFields(rI);
                    else
                    {
                        s.SetHexStr(databaseS.c_str());
                        v.SetHexStr(databaseV.c_str());
                    }

                    b.SetRand(19 * 8);
                    BigNumber gmod = g.ModExp(b, N);
                    B = ((v * 3) + gmod) % N;

                    ASSERT(gmod.GetNumBytes() <= 32);

                    BigNumber unk3;
                    unk3.SetRand(16 * 8);

                    ///- Fill the response packet with the result
                    pkt << uint8(REALM_AUTH_SUCCESS);

                    // B may be calculated < 32B so we force minimal length to 32B
                    pkt.append(B.AsByteArray(32), 32);      // 32 bytes
                    pkt << uint8(1);
                    pkt.append(g.AsByteArray(), 1);
                    pkt << uint8(32);
                    pkt.append(N.AsByteArray(32), 32);
                    pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes
                    pkt.append(unk3.AsByteArray(16), 16);
                    uint8 securityFlags = 0;
                    pkt << uint8(securityFlags);            // security flags (0x0...0x04)

                    if(securityFlags & 0x01)                // PIN input
                    {
                        pkt << uint32(0);
                        pkt << uint64(0) << uint64(0);      // 16 bytes hash?
                    }

                    if(securityFlags & 0x02)                // Matrix input
                    {
                        pkt << uint8(0);
                        pkt << uint8(0);
                        pkt << uint8(0);
                        pkt << uint8(0);
                        pkt << uint64(0);
                    }

                    if(securityFlags & 0x04)                // Security token input
                    {
                        pkt << uint8(1);
                    }

                    uint8 secLevel = (*result)[4].GetUInt8();
                    _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;

                    _localizationName.resize(4);
                    for(int i = 0; i < 4; ++i)
                        _localizationName[i] = ch->country[4-i-1];

                    sLog.outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName));

                    // user authenticated => turn off autoreg, thus account creating
                    _autoreg = false;
                }
            }
            delete result;
        }
        else if(_autoreg)                                   // no account
        {
            // check username
            if(_safelogin.find_first_of(notAllowedChars)!=_safelogin.npos || _safelogin.length()<4)
                _autoreg = false;
            // check IP
            else if(uint32 amountip = sConfig.GetIntDefault("AmountIP", 0))
            {
                QueryResult *result2 = loginDatabase.PQuery("SELECT COUNT(last_ip) FROM account WHERE last_ip = '%s'", GetRemoteAddress().c_str());
                if (result2 && (*result2)[0].GetUInt8() >= amountip)
                {
                    _autoreg = false;
                    delete result2;
                }
            }

            // still all ok
            if(_autoreg)
            {
                ///- Get the password from the account table, upper it, and make the SRP6 calculation
                std::transform(_safelogin.begin(), _safelogin.end(), _safelogin.begin(), std::towupper);
                Sha1Hash sha;
                std::string sI = _safelogin + ":" + _safelogin;
                sha.UpdateData(sI);
                sha.Finalize();

                BigNumber bn;
                bn.SetBinary(sha.GetDigest(), sha.GetLength());
                uint8 *val = bn.AsByteArray();
                std::reverse(val, val+bn.GetNumBytes());
                bn.SetBinary(val, bn.GetNumBytes());

                const char* rI = bn.AsHexStr();
                _SetVSFields(rI);
                OPENSSL_free((void*)rI);

                b.SetRand(19 * 8);
                BigNumber gmod=g.ModExp(b, N);
                B = ((v * 3) + gmod) % N;

                if (B.GetNumBytes() < 32)
                    sLog.outDetail("Interesting, calculation of B in realmd is < 32.");

                ASSERT(gmod.GetNumBytes() <= 32);

                BigNumber unk3;
                unk3.SetRand(16*8);

                ///- Fill the response packet with the result
                pkt << (uint8)REALM_AUTH_SUCCESS;
                pkt.append(B.AsByteArray(), 32);
                pkt << (uint8)1;
                pkt.append(g.AsByteArray(), 1);
                pkt << (uint8)32;
                pkt.append(N.AsByteArray(), 32);
                pkt.append(s.AsByteArray(), s.GetNumBytes());
                pkt.append(unk3.AsByteArray(), 16);
                pkt << (uint8)0;                // Added in 1.12.x client branch
            }
            else
                // username and/or IP is bad
                pkt << (uint8) REALM_AUTH_NO_MATCH;
        }
        else
        {
            // autoreg off in config, account is wrong
            pkt << (uint8) REALM_AUTH_NO_MATCH;
        }
    }
    SendBuf((char const*)pkt.contents(), pkt.size());
    return true;
}
Exemplo n.º 11
0
// Logon Proof command handler
bool AuthSession::HandleLogonProof()
{
    TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
    _status = STATUS_CLOSED;

    // Read the packet
    sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer().GetReadPointer());

    // If the client has no valid version
    if (_expversion == NO_VALID_EXP_FLAG)
    {
        // Check if we have the appropriate patch on the disk
        TC_LOG_DEBUG("network", "Client with invalid version, patching is not implemented");
        return false;
    }

    // Continue the SRP6 calculation based on data received from the client
    BigNumber A;

    A.SetBinary(logonProof->A, 32);

    // SRP safeguard: abort if A == 0
    if ((A % N).IsZero())
        return false;

    SHA1Hash sha;
    sha.UpdateBigNumbers(&A, &B, nullptr);
    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).get(), 32);

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2] = sha.GetDigest()[i];

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2 + 1];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2 + 1] = sha.GetDigest()[i];

    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, nullptr);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, nullptr);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        hash[i] ^= sha.GetDigest()[i];

    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_accountInfo.Login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, nullptr);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, nullptr);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), sha.GetLength());

    // Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20))
    {
        // Check auth token
        if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty())
        {
            uint8 size = *(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C));
            std::string token(reinterpret_cast<char*>(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size);
            GetReadBuffer().ReadCompleted(sizeof(size) + size);
            uint32 validToken = TOTP::GenerateToken(_tokenKey.c_str());
            _tokenKey.clear();
            uint32 incomingToken = atoi(token.c_str());
            if (validToken != incomingToken)
            {
                ByteBuffer packet;
                packet << uint8(AUTH_LOGON_PROOF);
                packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
                packet << uint8(3);
                packet << uint8(0);
                SendPacket(packet);
                return true;
            }
        }

        TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str());

        // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket

        PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
        stmt->setString(0, K.AsHexStr());
        stmt->setString(1, GetRemoteIpAddress().to_string());
        stmt->setUInt32(2, GetLocaleByName(_localizationName));
        stmt->setString(3, _os);
        stmt->setString(4, _accountInfo.Login);
        LoginDatabase.DirectExecute(stmt);

        // Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, nullptr);
        sha.Finalize();

        ByteBuffer packet;
        if (_expversion & POST_BC_EXP_FLAG)                 // 2.x and 3.x clients
        {
            sAuthLogonProof_S proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.AccountFlags = 0x00800000;    // 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
            proof.SurveyId = 0;
            proof.unk3 = 0;

            packet.resize(sizeof(proof));
            std::memcpy(packet.contents(), &proof, sizeof(proof));
        }
        else
        {
            sAuthLogonProof_S_Old proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.unk2 = 0x00;

            packet.resize(sizeof(proof));
            std::memcpy(packet.contents(), &proof, sizeof(proof));
        }

        SendPacket(packet);
        _status = STATUS_AUTHED;
    }
    else
    {
        ByteBuffer packet;
        packet << uint8(AUTH_LOGON_PROOF);
        packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
        packet << uint8(3);
        packet << uint8(0);
        SendPacket(packet);

        TC_LOG_INFO("server.authserver.hack", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!",
            GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str());

        uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0);

        // We can not include the failed account login hook. However, this is a workaround to still log this.
        if (sConfigMgr->GetBoolDefault("WrongPass.Logging", false))
        {
            PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING);
            logstmt->setUInt32(0, _accountInfo.Id);
            logstmt->setString(1, GetRemoteIpAddress().to_string());
            logstmt->setString(2, "Logged on failed AccountLogin due wrong password");

            LoginDatabase.Execute(logstmt);
        }

        if (MaxWrongPassCount > 0)
        {
            //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS);
            stmt->setString(0, _accountInfo.Login);
            LoginDatabase.Execute(stmt);

            if (++_accountInfo.FailedLogins >= MaxWrongPassCount)
            {
                uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600);
                bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false);

                if (WrongPassBanType)
                {
                    stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED);
                    stmt->setUInt32(0, _accountInfo.Id);
                    stmt->setUInt32(1, WrongPassBanTime);
                    LoginDatabase.Execute(stmt);

                    TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                        GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str(), WrongPassBanTime, _accountInfo.FailedLogins);
                }
                else
                {
                    stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED);
                    stmt->setString(0, GetRemoteIpAddress().to_string());
                    stmt->setUInt32(1, WrongPassBanTime);
                    LoginDatabase.Execute(stmt);

                    TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times",
                        GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), WrongPassBanTime, _accountInfo.Login.c_str(), _accountInfo.FailedLogins);
                }
            }
        }
    }

    return true;
}
Exemplo n.º 12
0
void WorldSocket::InformationRetreiveCallback(WorldPacket & recvData, uint32 requestid)
{
    if(requestid != mRequestID)
        return;

    uint32 error;
    recvData >> error;

    if(error != 0)
    {
        // something happened wrong @ the logon server
        OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
        printf("Information callback returns failure.\n");
        return;
    }

    // Extract account information from the packet.
    string AccountName;
    uint32 AccountID;
    string GMFlags;
    uint8 AccountFlags;

    recvData >> AccountID >> AccountName >> GMFlags >> AccountFlags;
    printf( " >> got information packet from logon: `%s` ID %u (request %u)", AccountName.c_str(), AccountID, mRequestID);
    //	sLog.outColor(TNORMAL, "\n");

    mRequestID = 0;
    //Pull the session key.

    recvData.read(K, 40);

    _crypt.Init(K);

    BigNumber BNK;
    BNK.SetBinary(K, 40);

    //checking if player is already connected
    //disconnect current player and login this one(blizzlike)

    string lang = "enUS";
    if(recvData.rpos() != recvData.wpos())
        recvData.read((uint8*)lang.data(), 4);

    Session * session = sClientMgr.CreateSession(AccountID);
    if(session == NULL)
    {
        /* we are already logged in. send auth failed. (if anyone has a better error lemme know :P) */
        OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
        printf("Duplicate client error.\n");
        return;
    }

    m_session = session;
    session->m_socket = this;
    Sha1Hash sha;

    uint8 digest[20];
    pAuthenticationPacket->read(digest, 20);

    uint32 t = 0;
    if( m_fullAccountName == NULL )				// should never happen !
        sha.UpdateData(AccountName);
    else
    {
        sha.UpdateData(*m_fullAccountName);

        // this is unused now. we may as well free up the memory.
        delete m_fullAccountName;
        m_fullAccountName = NULL;
    }

    sha.UpdateData((uint8 *)&t, 4);
    sha.UpdateData((uint8 *)&mClientSeed, 4);
    sha.UpdateData((uint8 *)&mSeed, 4);
    sha.UpdateBigNumbers(&BNK, NULL);
    sha.Finalize();

    if (memcmp(sha.GetDigest(), digest, 20))
    {
        // AUTH_UNKNOWN_ACCOUNT = 21
        OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15");
        return;
    }

    //_crypt.Init(digest);

    // Allocate session
    m_session->m_accountFlags = AccountFlags;
    m_session->m_GMPermissions = GMFlags;
    m_session->m_accountId = AccountID;
    m_session->m_latency = _latency;
    m_session->m_accountName = AccountName;
    m_session->m_ClientBuild = mClientBuild;

    Log.Notice("Auth", "%s from %s:%u [%ums]", AccountName.c_str(), GetRemoteIP().c_str(), GetRemotePort(), _latency);
    Authenticate();
}
Exemplo n.º 13
0
void WorldSocket::InformationRetreiveCallback(WorldPacket & recvData, uint32 requestid)
{
	if(requestid != mRequestID)
		return;

	uint32 error;
	recvData >> error;

	if(error != 0 || pAuthenticationPacket == NULL)
	{
		// something happened wrong @ the logon server
		OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
		return;
	}

	// Extract account information from the packet.
	string AccountName;
	const string * ForcedPermissions;
	uint32 AccountID;
	string GMFlags;
	uint8 AccountFlags;
	string lang = "enUS";
	uint32 i;

	recvData >> AccountID >> AccountName >> GMFlags >> AccountFlags;
	ForcedPermissions = sLogonCommHandler.GetForcedPermissions(AccountName);
	if( ForcedPermissions != NULL )
		GMFlags.assign(ForcedPermissions->c_str());

	DEBUG_LOG( "WorldSocket","Received information packet from logon: `%s` ID %u (request %u)", AccountName.c_str(), AccountID, mRequestID);

	mRequestID = 0;
	// Pull the session key.

	BigNumber BNK;
	recvData.read(K, 40);
	_crypt.Init(K);
	BNK.SetBinary(K, 40);

	//checking if player is already connected
	//disconnect current player and login this one(blizzlike)

	if(recvData.rpos() != recvData.wpos())
		recvData.read((uint8*)lang.data(), 4);

	WorldSession *session = NULL;
	session = sWorld.FindSession( AccountID );
	if( session != NULL )
	{
		if(session->_player != NULL && session->_player->GetMapMgr() == NULL)
		{
			DEBUG_LOG("WorldSocket","_player found without m_mapmgr during logon, trying to remove him [player %s, map %d, instance %d].", session->_player->GetName(), session->_player->GetMapId(), session->_player->GetInstanceID() );
			if(objmgr.GetPlayer(session->_player->GetLowGUID()))
				objmgr.RemovePlayer(session->_player);
			session->LogoutPlayer(false);
		}
		// AUTH_FAILED = 0x0D
		session->Disconnect();

		// clear the logout timer so he times out straight away
		session->SetLogoutTimer(1);

		// we must send authentication failed here.
		// the stupid newb can relog his client.
		// otherwise accounts dupe up and disasters happen.
		OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15");
		return;
	}

	Sha1Hash sha;

	uint8 digest[20];
	pAuthenticationPacket->read(digest, 20);

	uint32 t = 0;
	if( m_fullAccountName == NULL )				// should never happen !
		sha.UpdateData(AccountName);
	else
	{
		sha.UpdateData(*m_fullAccountName);
		
		// this is unused now. we may as well free up the memory.
		delete m_fullAccountName;
		m_fullAccountName = NULL;
	}

	sha.UpdateData((uint8 *)&t, 4);
	sha.UpdateData((uint8 *)&mClientSeed, 4);
	sha.UpdateData((uint8 *)&mSeed, 4);
	sha.UpdateBigNumbers(&BNK, NULL);
	sha.Finalize();

	if (memcmp(sha.GetDigest(), digest, 20))
	{
		// AUTH_UNKNOWN_ACCOUNT = 21
		OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15");
		return;
	}

	// Allocate session
	WorldSession * pSession = new WorldSession(AccountID, AccountName, this);
	mSession = pSession;
	ASSERT(mSession);
	pSession->deleteMutex.Acquire();

	// Set session properties
	pSession->permissioncount = 0; // just to make sure it's 0
	pSession->SetClientBuild(mClientBuild);
	pSession->LoadSecurity(GMFlags);
	pSession->SetAccountFlags(AccountFlags);
	pSession->m_lastPing = (uint32)UNIXTIME;

	if(recvData.rpos() != recvData.wpos())
		recvData >> pSession->m_muted;

	for(uint32 i = 0; i < 8; i++)
		pSession->SetAccountData(i, NULL, true, 0);

	if(sWorld.m_useAccountData)
	{
		QueryResult * pResult = CharacterDatabase.Query("SELECT * FROM account_data WHERE acct = %u", AccountID);
		if( pResult == NULL )
			CharacterDatabase.Execute("INSERT INTO account_data VALUES(%u, '', '', '', '', '', '', '', '', '')", AccountID);
		else
		{
			char * d;
			size_t len;
			const char * data;
			for(i = 0; i < 8; i++)
			{
				data = pResult->Fetch()[1+i].GetString();
				len = data ? strlen(data) : 0;
				if(len > 1)
				{
					d = new char[len+1];
					memcpy(d, data, len+1);
					pSession->SetAccountData(i, d, true, (uint32)len);
				}
			}

			delete pResult;
		}
	}

	DEBUG_LOG("Auth", "%s from %s:%u [%ums]", AccountName.c_str(), GetRemoteIP().c_str(), GetRemotePort(), _latency);
#ifdef SESSION_CAP
	if( sWorld.GetSessionCount() >= SESSION_CAP )
	{
		OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
		Disconnect();
		return;
	}
#endif

	// Check for queue.
	if( (sWorld.GetSessionCount() < sWorld.GetPlayerLimit()) || pSession->HasGMPermissions() ) 
		Authenticate();
	else
	{
		// Queued, sucker.
		uint32 Position = sWorld.AddQueuedSocket(this);
		mQueued = true;
		DEBUG_LOG("Queue", "%s added to queue in position %u", AccountName.c_str(), Position);

		// Send packet so we know what we're doing
		UpdateQueuePosition(Position);
	}

	pSession->deleteMutex.Release();
}
Exemplo n.º 14
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 ) );
}
Exemplo n.º 15
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");
}
Exemplo n.º 16
0
/// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
    DEBUG_LOG("Entering _HandleLogonProof");
    ///- Read the packet
    if (ibuf.GetLength() < sizeof(sAuthLogonProof_C))
        return false;

    sAuthLogonProof_C lp;
    ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C));

    ///- Continue the SRP6 calculation based on data received from the client
    BigNumber A;
    A.SetBinary(lp.A, 32);

    Sha1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(), 32);
    for (int i = 0; i < 16; i++)
    {
        t1[i] = t[i*2];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; i++)
    {
        vK[i*2] = sha.GetDigest()[i];
    }
    for (int i = 0; i < 16; i++)
    {
        t1[i] = t[i*2+1];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; i++)
    {
        vK[i*2+1] = sha.GetDigest()[i];
    }
    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();
    for (int i = 0; i < 20; i++)
    {
        hash[i] ^= sha.GetDigest()[i];
    }
    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    BigNumber t4;
    t4.SetBinary(sha.GetDigest(), 20);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, &t4, &s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    ///- Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(), lp.M1, 20))
    {
        sLog.outBasic("User '%s' successfully authenticated", _login.c_str());

        ///- Update the sessionkey, last_ip and last login time in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        dbRealmServer.PExecute("UPDATE `account` SET `sessionkey` = '%s', `last_ip` = '%s', `last_login` = NOW(), `locale` = '%u' WHERE `username` = '%s'",K.AsHexStr(), GetRemoteAddress().c_str(),  _localization, _safelogin.c_str() );

        ///- Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        sAuthLogonProof_S proof;
        memcpy(proof.M2, sha.GetDigest(), 20);
        proof.cmd = AUTH_LOGON_PROOF;
        proof.error = 0;
        proof.unk2 = 0;
        proof.unk3 = 0;

        SendBuf((char *)&proof, sizeof(proof));

        ///- Set _authed to true!
        _authed = true;
    }
    else
    {
        char data[4]={AUTH_LOGON_PROOF,REALM_AUTH_NO_MATCH,3,0};
        SendBuf(data,sizeof(data));
    }
    return true;
}
Exemplo n.º 17
0
/// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
    DEBUG_LOG("Entering _HandleLogonProof");
    ///- Read the packet
    if (ibuf.GetLength() < sizeof(sAuthLogonProof_C))
        return false;

    sAuthLogonProof_C lp;
    ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C));

    ///- Continue the SRP6 calculation based on data received from the client
    BigNumber A;
    A.SetBinary(lp.A, 32);

    Sha1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(), 32);
    for (int i = 0; i < 16; i++)
    {
        t1[i] = t[i*2];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; i++)
    {
        vK[i*2] = sha.GetDigest()[i];
    }
    for (int i = 0; i < 16; i++)
    {
        t1[i] = t[i*2+1];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; i++)
    {
        vK[i*2+1] = sha.GetDigest()[i];
    }
    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();
    for (int i = 0; i < 20; i++)
    {
        hash[i] ^= sha.GetDigest()[i];
    }
    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, NULL);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    ///- Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(), lp.M1, 20))
    {
        sLog.outBasic("User '%s' successfully authenticated", _login.c_str());

        ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        const char* K_hex = K.AsHexStr();
        dbRealmServer.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, GetRemoteAddress().c_str(),  _localization, _safelogin.c_str() );
        OPENSSL_free((void*)K_hex);

        ///- Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        sAuthLogonProof_S proof;
        memcpy(proof.M2, sha.GetDigest(), 20);
        proof.cmd = AUTH_LOGON_PROOF;
        proof.error = 0;
        proof.unk1 = 0x00800000;
        proof.unk2 = 0x00;
        proof.unk3 = 0x00;

        SendBuf((char *)&proof, sizeof(proof));

        ///- Set _authed to true!
        _authed = true;
    }
    else
    {
        char data[4]={AUTH_LOGON_PROOF,REALM_AUTH_NO_MATCH,3,0};
        SendBuf(data,sizeof(data));
        sLog.outBasic("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ());

        uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0);
        if(MaxWrongPassCount > 0)
        {
            //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            dbRealmServer.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'",_safelogin.c_str());

            if(QueryResult *loginfail = dbRealmServer.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str()))
            {
                Field* fields = loginfail->Fetch();
                uint32 failed_logins = fields[1].GetUInt32();

                if( failed_logins >= MaxWrongPassCount )
                {
                    uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600);
                    bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false);

                    if(WrongPassBanType)
                    {
                        uint32 acc_id = fields[0].GetUInt32();
                        dbRealmServer.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)",
                            acc_id, WrongPassBanTime);
                        sLog.outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                            _login.c_str(), WrongPassBanTime, failed_logins);
                    }
                    else
                    {
                        std::string current_ip = GetRemoteAddress();
                        dbRealmServer.escape_string(current_ip);
                        dbRealmServer.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')",
                            current_ip.c_str(), WrongPassBanTime);
                        sLog.outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times",
                            current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
                    }
                }
                delete loginfail;
            }
        }
    }
    return true;
}
Exemplo n.º 18
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;



}
Exemplo n.º 19
0
// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
    sLog->outStaticDebug("Entering _HandleLogonProof");
    // Read the packet
    sAuthLogonProof_C lp;

    if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C)))
        return false;

    // If the client has no valid version
    if (_expversion == NO_VALID_EXP_FLAG)
    {
        // Check if we have the appropriate patch on the disk
        sLog->outDebug("Client with invalid version, patching is not implemented");
        socket().shutdown();
        return true;
    }

    // Continue the SRP6 calculation based on data received from the client
    BigNumber A;

    A.SetBinary(lp.A, 32);

    // SRP safeguard: abort if A == 0
    if (A.isZero())
    {
        socket().shutdown();
        return true;
    }

    SHA1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(32), 32);

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2] = sha.GetDigest()[i];

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2 + 1];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2 + 1] = sha.GetDigest()[i];

    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        hash[i] ^= sha.GetDigest()[i];

    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, NULL);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    // Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(), lp.M1, 20))
    {
        sLog->outBasic("'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());

        // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        const char *K_hex = K.AsHexStr();

        LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', os = '%s', failed_logins = 0 WHERE username = '******'", K_hex, socket().getRemoteAddress().c_str(), GetLocaleByName(_localizationName),
        _os.c_str(), _login.c_str());
        OPENSSL_free((void*)K_hex);

        // Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        if ((_expversion & POST_BC_EXP_FLAG) || (_expversion & POST_WOTLK_EXP_FLAG))     // 2.x, 3.x, 4.x
        {
            sAuthLogonProof_S proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.unk1 = 0x00800000;
            proof.unk2 = 0x00;
            proof.unk3 = 0x00;
            socket().send((char *)&proof, sizeof(proof));
        }
        else
        {
            sAuthLogonProof_S_Old proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.unk2 = 0x00;
            socket().send((char *)&proof, sizeof(proof));
        }

        _authed = true;
    }
    else
    {
        char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 };
        socket().send(data, sizeof(data));

        sLog->outBasic("'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ());

        uint32 MaxWrongPassCount = ConfigMgr::GetIntDefault("WrongPass.MaxCount", 0);
        if (MaxWrongPassCount > 0)
        {
            //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'",_login.c_str());

            if (QueryResult_AutoPtr loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _login.c_str()))
            {
                uint32 failed_logins = (*loginfail)[1].GetUInt32();

                if (failed_logins >= MaxWrongPassCount)
                {
                    uint32 WrongPassBanTime = ConfigMgr::GetIntDefault("WrongPass.BanTime", 600);
                    bool WrongPassBanType = ConfigMgr::GetBoolDefault("WrongPass.BanType", false);

                    if (WrongPassBanType)
                    {
                        uint32 acc_id = (*loginfail)[0].GetUInt32();
                        LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Skyfire realmd','Failed login autoban',1)",
                            acc_id, WrongPassBanTime);

                        sLog->outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                            _login.c_str(), WrongPassBanTime, failed_logins);
                    }
                    else
                    {
                        std::string current_ip(socket().getRemoteAddress().c_str());
                        LoginDatabase.EscapeString(current_ip);
                        LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Skyfire realmd','Failed login autoban')",
                            current_ip.c_str(), WrongPassBanTime);

                        sLog->outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", socket().getRemoteAddress().c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
                    }
                }
            }
        }
    }

    return true;
}
Exemplo n.º 20
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);
}
Exemplo n.º 21
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));
}
Exemplo n.º 22
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);
}
Exemplo n.º 23
0
/// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
    DEBUG_LOG("Entering _HandleLogonProof");
    ///- Read the packet
    if (ibuf.GetLength() < sizeof(sAuthLogonProof_C))
        return false;
    sAuthLogonProof_C lp;
    ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C));

    ///- Check if the client has one of the expected version numbers
    bool valid_version = FindBuildInfo(_build) != NULL;

    /// <ul><li> If the client has no valid version
    /// Ignore if its trial client account
    if(!valid_version && !_isTrial)
    {
        ///- Check if we have the apropriate patch on the disk

        // 24 = len("./patches/65535enGB.mpq")+1
        char tmp[24];
        // No buffer overflow (fixed length of arguments)
        sprintf(tmp, "./patches/%d%s.mpq", _build, _localizationName.c_str());
        // This will be closed at the destruction of the AuthSocket (client disconnection)
        FILE *pFile = fopen(tmp, "rb");

        if(!pFile)
        {
            ByteBuffer pkt;
            pkt << (uint8) AUTH_LOGON_CHALLENGE;
            pkt << (uint8) 0x00;
            pkt << (uint8) WOW_FAIL_VERSION_INVALID;
            DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build);
            DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp);
            SendBuf((char const*)pkt.contents(), pkt.size());
            return true;
        }
        else                                                // have patch
        {
            pPatch = pFile;
            XFER_INIT xferh;

            ///- Get the MD5 hash of the patch file (get it from preloaded Patcher cache or calculate it)
            if(PatchesCache.GetHash(tmp, (uint8*)&xferh.md5))
            {
                DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s", tmp);
            }
            else
            {                                               // calculate patch md5
                printf("\n[AuthChallenge] Patch info for %s was not cached.", tmp);
                PatchesCache.LoadPatchMD5(tmp);
                PatchesCache.GetHash(tmp, (uint8*)&xferh.md5);
            }

            ///- Send a packet to the client with the file length and MD5 hash
            uint8 data[2] = { AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE };
            SendBuf((const char*)data, sizeof(data));

            memcpy(&xferh, "0\x05Patch", 7);
            xferh.cmd = XFER_INITIATE;
            fseek(pPatch, 0, SEEK_END);
            xferh.file_size = ftell(pPatch);

            SendBuf((const char*)&xferh, sizeof(xferh));
            return true;
        }
    }
    /// </ul>

    ///- Continue the SRP6 calculation based on data received from the client
    BigNumber A;

    A.SetBinary(lp.A, 32);

    // SRP safeguard: abort if A==0
    if (A.isZero())
        return false;

    Sha1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(32), 32);
    for (int i = 0; i < 16; ++i)
    {
        t1[i] = t[i * 2];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; ++i)
    {
        vK[i * 2] = sha.GetDigest()[i];
    }
    for (int i = 0; i < 16; ++i)
    {
        t1[i] = t[i * 2 + 1];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; ++i)
    {
        vK[i * 2 + 1] = sha.GetDigest()[i];
    }
    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();
    for (int i = 0; i < 20; ++i)
    {
        hash[i] ^= sha.GetDigest()[i];
    }
    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, NULL);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    ///- Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(), lp.M1, 20))
    {
        BASIC_LOG("User '%s' successfully authenticated", _login.c_str());

        ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        const char* K_hex = K.AsHexStr();
        loginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, GetRemoteAddress().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str() );
        OPENSSL_free((void*)K_hex);

        ///- Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        SendProof(sha);

        ///- Set _authed to true!
        _authed = true;
    }
    else
    {
        char data[4]= { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0};
        SendBuf(data, sizeof(data));
        BASIC_LOG("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ());

        uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0);
        if(MaxWrongPassCount > 0)
        {
            //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            loginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'",_safelogin.c_str());

            if(QueryResult *loginfail = loginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str()))
            {
                Field* fields = loginfail->Fetch();
                uint32 failed_logins = fields[1].GetUInt32();

                if( failed_logins >= MaxWrongPassCount )
                {
                    uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600);
                    bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false);

                    if(WrongPassBanType)
                    {
                        uint32 acc_id = fields[0].GetUInt32();
                        loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)",
                            acc_id, WrongPassBanTime);
                        BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                            _login.c_str(), WrongPassBanTime, failed_logins);
                    }
                    else
                    {
                        std::string current_ip = GetRemoteAddress();
                        loginDatabase.escape_string(current_ip);
                        loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')",
                            current_ip.c_str(), WrongPassBanTime);
                        BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times",
                            current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
                    }
                }
                delete loginfail;
            }
        }
    }
    return true;
}
Exemplo n.º 24
0
void AccountMgr::AddAccount(Field* field)
{
	Account * acct = new Account;
	Sha1Hash hash;
	string Username     = field[1].GetString();
	string Password	    = field[2].GetString();
	//string EncryptedPassword = field[3].GetString();
	string GMFlags		= field[3].GetString();

	acct->AccountId				= field[0].GetUInt32();
	acct->AccountFlags			= field[4].GetUInt8();
	acct->Banned				= field[5].GetUInt32();
	if ( (uint32)UNIXTIME > acct->Banned && acct->Banned != 0 && acct->Banned != 1) //1 = perm ban?
	{
		//Accounts should be unbanned once the date is past their set expiry date.
		acct->Banned = 0;
		//me go boom :(
		//printf("Account %s's ban has expired.\n",acct->UsernamePtr->c_str());
		sLogonSQL->Execute("UPDATE accounts SET banned = 0 WHERE acct=%u",acct->AccountId);
	}
	acct->SetGMFlags(GMFlags.c_str());
	acct->Locale[0] = 'e';
	acct->Locale[1] = 'n';
	acct->Locale[2] = 'U';
	acct->Locale[3] = 'S';
	if(strcmp(field[6].GetString(), "enUS"))
	{
		// non-standard language forced
		memcpy(acct->Locale, field[6].GetString(), 4);
		acct->forcedLocale = true;
	}
	else
		acct->forcedLocale = false;

    acct->Muted = field[7].GetUInt32();
	if ( (uint32)UNIXTIME > acct->Muted && acct->Muted != 0 && acct->Muted != 1) //1 = perm ban?
	{
		//Accounts should be unbanned once the date is past their set expiry date.
		acct->Muted= 0;
		DEBUG_LOG("AccountMgr","Account %s's mute has expired.", Username.c_str());
		sLogonSQL->Execute("UPDATE accounts SET muted = 0 WHERE acct=%u",acct->AccountId);
	}
	// Convert username/password to uppercase. this is needed ;)
	HEARTHSTONE_TOUPPER(Username);
	HEARTHSTONE_TOUPPER(Password);
	
	if( m_encryptedPasswords )
	{
		// prefer encrypted passwords over nonencrypted
		BigNumber bn;
		bn.SetHexStr( Password.c_str() );
		if( bn.GetNumBytes() != 20 )
		{
			// Someone probably has non-encrypted passwords in a server that's set to encrypted pws.
			hash.UpdateData((Username + ":" + Password));
			hash.Finalize();
			memcpy(acct->SrpHash, hash.GetDigest(), 20);
			// Make sure this doesn't happen again.
			BigNumber cnSave;
			cnSave.SetBinary( acct->SrpHash, 20);
			string hash = cnSave.AsHexStr();
			DEBUG_LOG("AccountMgr", "Found account %s [%u] with invalid password format. Converting to encrypted password.", Username.c_str(), acct->AccountId);
			sLogonSQL->Execute("UPDATE accounts SET password = SHA1(CONCAT(UPPER(login), ':', UPPER(password))) WHERE acct = %u", acct->AccountId);
		}
		else
		{
			if ( Password.size() == 40 )
			{
				if( bn.GetNumBytes() < 20 )
				{
					memcpy(acct->SrpHash, bn.AsByteArray(), bn.GetNumBytes());
					for (int n=bn.GetNumBytes(); n<=19; n++)
						acct->SrpHash[n] = (uint8)0;
					reverse_array(acct->SrpHash, 20);
				}
				else
				{
					memcpy(acct->SrpHash, bn.AsByteArray(), 20);
					reverse_array(acct->SrpHash, 20);
				}
			}
		}
	}
	else
	{
		// Prehash the I value.
		hash.UpdateData((Username + ":" + Password));
		hash.Finalize();
		memcpy(acct->SrpHash, hash.GetDigest(), 20);
	}

	AccountDatabase[Username] = acct;
}
Exemplo n.º 25
0
bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacket** response)
{
    if (dataStream->GetSize() != 1 + 128 + 32 + 128)
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
        ReplaceResponse(response, logonResponse);
        return false;
    }

    if (dataStream->Read<uint8>(8) != 2)                // State
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
        ReplaceResponse(response, logonResponse);
        return false;
    }

    BigNumber A, clientM1, clientChallenge;
    A.SetBinary(dataStream->ReadBytes(128).get(), 128);
    clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32);
    clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128);

    if (A.isZero())
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
        ReplaceResponse(response, logonResponse);
        return false;
    }

    SHA256Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();

    BigNumber u;
    u.SetBinary(sha.GetDigest(), sha.GetLength());

    BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N);

    uint8 S_bytes[128];
    memcpy(S_bytes, S.AsByteArray(128).get(), 128);

    uint8 part1[64];
    uint8 part2[64];

    for (int i = 0; i < 64; ++i)
    {
        part1[i] = S_bytes[i * 2];
        part2[i] = S_bytes[i * 2 + 1];
    }

    SHA256Hash part1sha, part2sha;
    part1sha.UpdateData(part1, 64);
    part1sha.Finalize();
    part2sha.UpdateData(part2, 64);
    part2sha.Finalize();

    uint8 sessionKey[SHA256_DIGEST_LENGTH * 2];
    for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
    {
        sessionKey[i * 2] = part1sha.GetDigest()[i];
        sessionKey[i * 2 + 1] = part2sha.GetDigest()[i];
    }

    K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2);

    BigNumber M1;

    uint8 hash[SHA256_DIGEST_LENGTH];
    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), sha.GetLength());

    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();

    for (int i = 0; i < sha.GetLength(); ++i)
        hash[i] ^= sha.GetDigest()[i];

    SHA256Hash shaI;
    shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32));
    shaI.Finalize();

    // Concat all variables for M1 hash
    sha.Initialize();
    sha.UpdateData(hash, SHA256_DIGEST_LENGTH);
    sha.UpdateData(shaI.GetDigest(), shaI.GetLength());
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();

    M1.SetBinary(sha.GetDigest(), sha.GetLength());

    if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32))
    {
        PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS);
        stmt->setString(0, _accountInfo->Login);
        LoginDatabase.Execute(stmt);

        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
        ReplaceResponse(response, logonResponse);
        TC_LOG_DEBUG("session", "[Battlenet::Password] %s attempted to log in with invalid password!", GetClientInfo().c_str());
        return false;
    }

    if (_gameAccounts.empty())
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
        ReplaceResponse(response, logonResponse);
        TC_LOG_DEBUG("session", "[Battlenet::Password] %s does not have any linked game accounts!", GetClientInfo().c_str());
        return false;
    }

    BigNumber M;
    sha.Initialize();
    sha.UpdateBigNumbers(&A, &M1, &K, NULL);
    sha.Finalize();
    M.SetBinary(sha.GetDigest(), sha.GetLength());

    BigNumber serverProof;
    serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client

    BitStream stream;
    ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password");
    uint8 state = 3;

    stream.WriteBytes(&state, 1);
    stream.WriteBytes(M.AsByteArray(32).get(), 32);
    stream.WriteBytes(serverProof.AsByteArray(128).get(), 128);

    password->DataSize = stream.GetSize();
    password->Data = new uint8[password->DataSize];
    memcpy(password->Data, stream.GetBuffer(), password->DataSize);

    Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest();
    proofRequest->Modules.push_back(password);
    if (_gameAccounts.size() > 1)
    {
        BitStream accounts;
        state = 0;
        accounts.WriteBytes(&state, 1);
        accounts.Write(_gameAccounts.size(), 8);
        for (GameAccountInfo const& gameAccount : _gameAccounts)
        {
            accounts.Write(2, 8);
            accounts.WriteString(gameAccount.DisplayName, 8);
        }

        ModuleInfo* selectGameAccount = sModuleMgr->CreateModule(_os, "SelectGameAccount");
        selectGameAccount->DataSize = accounts.GetSize();
        selectGameAccount->Data = new uint8[selectGameAccount->DataSize];
        memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize);
        proofRequest->Modules.push_back(selectGameAccount);
        _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT);
    }
    else
    {
        _gameAccountInfo = &_gameAccounts[0];

        if (_gameAccountInfo->IsBanned)
        {
            delete proofRequest;

            Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
            if (_gameAccountInfo->IsPermanentlyBanned)
            {
                logonResponse->SetAuthResult(LOGIN_BANNED);
                TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str());
            }
            else
            {
                logonResponse->SetAuthResult(LOGIN_SUSPENDED);
                TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str());
            }

            ReplaceResponse(response, logonResponse);
            return false;
        }

        proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint"));
        _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT);
    }

    ReplaceResponse(response, proofRequest);
    return true;
}
Exemplo n.º 26
0
void WorldSocket::InformationRetreiveCallback(WorldPacket & recvData, uint32 requestid)
{
    if(requestid != mRequestID)
        return;

    uint32 error;
    recvData >> error;

    if(error != 0 || pAuthenticationPacket == NULL)
    {
        // something happened wrong @ the logon server
        OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
        return;
    }

    // Extract account information from the packet.
    string AccountName;
    const string * ForcedPermissions;
    uint32 AccountID;
    string GMFlags;
    uint8 AccountFlags;
    string lang = "enUS";
    uint32 i;

    recvData >> AccountID >> AccountName >> GMFlags >> AccountFlags;
    ForcedPermissions = sLogonCommHandler.GetForcedPermissions(AccountName);
    if( ForcedPermissions != NULL )
        GMFlags.assign(ForcedPermissions->c_str());

    sLog.outDebug( " >> got information packet from logon: `%s` ID %u (request %u)", AccountName.c_str(), AccountID, mRequestID);
//	sLog.outColor(TNORMAL, "\n");

    mRequestID = 0;
    // Pull the session key.
    uint8 K[40];
    recvData.read(K, 40);

    BigNumber BNK;
    BNK.SetBinary(K, 40);

    uint8 *key = new uint8[20];
    WowCrypt::GenerateKey(key, K);

    // Initialize crypto.
    _crypt.SetKey(key, 20);
    _crypt.Init();
    delete [] key;

    //checking if player is already connected
    //disconnect corrent player and login this one(blizzlike)

    if(recvData.rpos() != recvData.wpos())
        recvData.read((uint8*)lang.data(), 4);

    WorldSession *session = sWorld.FindSession( AccountID );
    if( session)
    {
        // AUTH_FAILED = 0x0D
        session->Disconnect();

        // clear the logout timer so he times out straight away
        session->SetLogoutTimer(1);

        // we must send authentication failed here.
        // the stupid newb can relog his client.
        // otherwise accounts dupe up and disasters happen.
        OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15");
        return;
    }

    Sha1Hash sha;

    uint8 digest[20];
    pAuthenticationPacket->read(digest, 20);

    uint32 t = 0;
    if( m_fullAccountName == NULL )				// should never happen !
        sha.UpdateData(AccountName);
    else
    {
        sha.UpdateData(*m_fullAccountName);

        // this is unused now. we may as well free up the memory.
        delete m_fullAccountName;
        m_fullAccountName = NULL;
    }

    sha.UpdateData((uint8 *)&t, 4);
    sha.UpdateData((uint8 *)&mClientSeed, 4);
    sha.UpdateData((uint8 *)&mSeed, 4);
    sha.UpdateBigNumbers(&BNK, NULL);
    sha.Finalize();

    if (memcmp(sha.GetDigest(), digest, 20))
    {
        // AUTH_UNKNOWN_ACCOUNT = 21
        OutPacket(SMSG_AUTH_RESPONSE, 1, "\x15");
        return;
    }

    // Allocate session
    WorldSession * pSession = new WorldSession(AccountID, AccountName, this);
    mSession = pSession;
    ASSERT(mSession);
    pSession->deleteMutex.Acquire();

    // Set session properties
    pSession->SetClientBuild(mClientBuild);
    pSession->LoadSecurity(GMFlags);
    pSession->SetAccountFlags(AccountFlags);
    pSession->m_lastPing = (uint32)UNIXTIME;
    pSession->language = sLocalizationMgr.GetLanguageId(lang);

    if(recvData.rpos() != recvData.wpos())
        recvData >> pSession->m_muted;

    for(uint32 i = 0; i < 8; ++i)
        pSession->SetAccountData(i, NULL, true, 0);

    // queue the account loading
    /*AsyncQuery * aq = new AsyncQuery( new SQLClassCallbackP1<World, uint32>(World::getSingletonPtr(), &World::LoadAccountDataProc, AccountID) );
    aq->AddQuery("SELECT * FROM account_data WHERE acct = %u", AccountID);
    CharacterDatabase.QueueAsyncQuery(aq);*/
    if(sWorld.m_useAccountData)
    {
        QueryResult * pResult = CharacterDatabase.Query("SELECT * FROM account_data WHERE acct = %u", AccountID);
        if( pResult == NULL )
            CharacterDatabase.Execute("INSERT INTO account_data VALUES(%u, '', '', '', '', '', '', '', '', '')", AccountID);
        else
        {
            size_t len;
            const char * data;
            char * d;
            for(i = 0; i < 8; ++i)
            {
                data = pResult->Fetch()[1+i].GetString();
                len = data ? strlen(data) : 0;
                if(len > 1)
                {
                    d = new char[len+1];
                    memcpy(d, data, len+1);
                    pSession->SetAccountData(i, d, true, (uint32)len);
                }
            }

            delete pResult;
        }
    }

    Log.Debug("Auth", "%s from %s:%u [%ums]", AccountName.c_str(), GetRemoteIP().c_str(), GetRemotePort(), _latency);
#ifdef SESSION_CAP
    if( sWorld.GetSessionCount() >= SESSION_CAP )
    {
        OutPacket(SMSG_AUTH_RESPONSE, 1, "\x0D");
        Disconnect();
        return;
    }
#endif

    // Check for queue.
    if( (sWorld.GetSessionCount() < sWorld.GetPlayerLimit()) || pSession->HasGMPermissions() ) {
        Authenticate();
    } else {
        // Queued, sucker.
        uint32 Position = sWorld.AddQueuedSocket(this);
        mQueued = true;
        Log.Debug("Queue", "%s added to queue in position %u", AccountName.c_str(), Position);

        // Send packet so we know what we're doing
        UpdateQueuePosition(Position);
    }

    pSession->deleteMutex.Release();
}
Exemplo n.º 27
0
// Logon Proof command handler
bool AuthSession::_HandleLogonProof()
{

    TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
    // Read the packet
    sAuthLogonProof_C *logonProof = (sAuthLogonProof_C*)&_readBuffer;

    // If the client has no valid version
    if (_expversion == NO_VALID_EXP_FLAG)
    {
        // Check if we have the appropriate patch on the disk
        TC_LOG_DEBUG("network", "Client with invalid version, patching is not implemented");
        return false;
    }

    // Continue the SRP6 calculation based on data received from the client
    BigNumber A;

    A.SetBinary(logonProof->A, 32);

    // SRP safeguard: abort if A == 0
    if (A.isZero())
    {
        return false;
    }

    SHA1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(32).get(), 32);

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2] = sha.GetDigest()[i];

    for (int i = 0; i < 16; ++i)
        t1[i] = t[i * 2 + 1];

    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        vK[i * 2 + 1] = sha.GetDigest()[i];

    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();

    for (int i = 0; i < 20; ++i)
        hash[i] ^= sha.GetDigest()[i];

    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, NULL);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    // Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20))
    {
        TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str());

        // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        const char *K_hex = K.AsHexStr();

        PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
        stmt->setString(0, K_hex);
        stmt->setString(1, GetRemoteIpAddress().c_str());
        stmt->setUInt32(2, GetLocaleByName(_localizationName));
        stmt->setString(3, _os);
        stmt->setString(4, _login);
        LoginDatabase.DirectExecute(stmt);

        OPENSSL_free((void*)K_hex);

        // Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        // Check auth token
        if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty())
        {
            // TODO To be fixed

            /*
            uint8 size;
            socket().recv((char*)&size, 1);
            char* token = new char[size + 1];
            token[size] = '\0';
            socket().recv(token, size);
            unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str());
            unsigned int incomingToken = atoi(token);
            delete[] token;
            if (validToken != incomingToken)
            {
            char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 };
            socket().send(data, sizeof(data));
            return false;
            }*/
        }

        if (_expversion & POST_BC_EXP_FLAG)                 // 2.x and 3.x clients
        {
            sAuthLogonProof_S proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.unk1 = 0x00800000;    // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
            proof.unk2 = 0x00;          // SurveyId
            proof.unk3 = 0x00;

            std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof));
            AsyncWrite(sizeof(proof));
        }
        else
        {
            sAuthLogonProof_S_Old proof;
            memcpy(proof.M2, sha.GetDigest(), 20);
            proof.cmd = AUTH_LOGON_PROOF;
            proof.error = 0;
            proof.unk2 = 0x00;

            std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof));
            AsyncWrite(sizeof(proof));
        }

        _isAuthenticated = true;
    }
    else
    {
        char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 };

        std::memcpy(_writeBuffer, data, sizeof(data));
        AsyncWrite(sizeof(data));

        TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!",
                     GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str());

        uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0);

        // We can not include the failed account login hook. However, this is a workaround to still log this.
        if (sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false))
        {
            PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING);
            logstmt->setString(0, _login);
            logstmt->setString(1, GetRemoteIpAddress());
            logstmt->setString(2, "Logged on failed AccountLogin due wrong password");

            LoginDatabase.Execute(logstmt);
        }

        if (MaxWrongPassCount > 0)
        {
            //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS);
            stmt->setString(0, _login);
            LoginDatabase.Execute(stmt);

            stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS);
            stmt->setString(0, _login);

            if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt))
            {
                uint32 failed_logins = (*loginfail)[1].GetUInt32();

                if (failed_logins >= MaxWrongPassCount)
                {
                    uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600);
                    bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false);

                    if (WrongPassBanType)
                    {
                        uint32 acc_id = (*loginfail)[0].GetUInt32();
                        stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED);
                        stmt->setUInt32(0, acc_id);
                        stmt->setUInt32(1, WrongPassBanTime);
                        LoginDatabase.Execute(stmt);

                        TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                                     GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins);
                    }
                    else
                    {
                        stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED);
                        stmt->setString(0, GetRemoteIpAddress());
                        stmt->setUInt32(1, WrongPassBanTime);
                        LoginDatabase.Execute(stmt);

                        TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times",
                                     GetRemoteIpAddress().c_str(), GetRemotePort(), WrongPassBanTime, _login.c_str(), failed_logins);
                    }
                }
            }
        }
    }

    return true;
}
Exemplo n.º 28
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);
}
Exemplo n.º 29
0
/// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
    DEBUG_LOG("Entering _HandleLogonProof");
    ///- Read the packet
    sAuthLogonProof_C lp;
    if (!recv((char*)&lp, sizeof(sAuthLogonProof_C)))
        return false;

    ///- Check if the client has one of the expected version numbers
    bool valid_version = FindBuildInfo(_build) != NULL;

    /// <ul><li> If the client has no valid version
    if (!valid_version)
    {
        if (this->patch_ != ACE_INVALID_HANDLE)
            return false;

        ///- Check if we have the apropriate patch on the disk
        // file looks like: 65535enGB.mpq
        char tmp[64];

        snprintf(tmp, 24, "./patches/%d%s.mpq", _build, _localizationName.c_str());

        char filename[PATH_MAX];
        if (ACE_OS::realpath(tmp, filename) != NULL)
        {
            patch_ = ACE_OS::open(filename, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN);
        }

        if (patch_ == ACE_INVALID_HANDLE)
        {
            // no patch found
            ByteBuffer pkt;
            pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE;
            pkt << (uint8) 0x00;
            pkt << (uint8) WOW_FAIL_VERSION_INVALID;
            DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build);
            DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp);
            send((char const*)pkt.contents(), pkt.size());
            return true;
        }

        XFER_INIT xferh;

        ACE_OFF_T file_size = ACE_OS::filesize(this->patch_);

        if (file_size == -1)
        {
            close_connection();
            return false;
        }

        if (!PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5))
        {
            // calculate patch md5, happens if patch was added while realmd was running
            PatchCache::instance()->LoadPatchMD5(tmp);
            PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5);
        }

        uint8 data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE};
        send((const char*)data, sizeof(data));

        memcpy(&xferh, "0\x05Patch", 7);
        xferh.cmd = CMD_XFER_INITIATE;
        xferh.file_size = file_size;

        send((const char*)&xferh, sizeof(xferh));
        return true;
    }
    /// </ul>

    ///- Continue the SRP6 calculation based on data received from the client
    BigNumber A;

    A.SetBinary(lp.A, 32);

    // SRP safeguard: abort if A==0
    if (A.isZero())
        return false;

    Sha1Hash sha;
    sha.UpdateBigNumbers(&A, &B, NULL);
    sha.Finalize();
    BigNumber u;
    u.SetBinary(sha.GetDigest(), 20);
    BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);

    uint8 t[32];
    uint8 t1[16];
    uint8 vK[40];
    memcpy(t, S.AsByteArray(32), 32);
    for (int i = 0; i < 16; ++i)
    {
        t1[i] = t[i * 2];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; ++i)
    {
        vK[i * 2] = sha.GetDigest()[i];
    }
    for (int i = 0; i < 16; ++i)
    {
        t1[i] = t[i * 2 + 1];
    }
    sha.Initialize();
    sha.UpdateData(t1, 16);
    sha.Finalize();
    for (int i = 0; i < 20; ++i)
    {
        vK[i * 2 + 1] = sha.GetDigest()[i];
    }
    K.SetBinary(vK, 40);

    uint8 hash[20];

    sha.Initialize();
    sha.UpdateBigNumbers(&N, NULL);
    sha.Finalize();
    memcpy(hash, sha.GetDigest(), 20);
    sha.Initialize();
    sha.UpdateBigNumbers(&g, NULL);
    sha.Finalize();
    for (int i = 0; i < 20; ++i)
    {
        hash[i] ^= sha.GetDigest()[i];
    }
    BigNumber t3;
    t3.SetBinary(hash, 20);

    sha.Initialize();
    sha.UpdateData(_login);
    sha.Finalize();
    uint8 t4[SHA_DIGEST_LENGTH];
    memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);

    sha.Initialize();
    sha.UpdateBigNumbers(&t3, NULL);
    sha.UpdateData(t4, SHA_DIGEST_LENGTH);
    sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
    sha.Finalize();
    BigNumber M;
    M.SetBinary(sha.GetDigest(), 20);

    ///- Check if SRP6 results match (password is correct), else send an error
    if (!memcmp(M.AsByteArray(), lp.M1, 20))
    {
        BASIC_LOG("User '%s' successfully authenticated", _login.c_str());

        ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
        // No SQL injection (escaped user name) and IP address as received by socket
        const char* K_hex = K.AsHexStr();
        LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, get_remote_address().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str());
        OPENSSL_free((void*)K_hex);

        ///- Finish SRP6 and send the final result to the client
        sha.Initialize();
        sha.UpdateBigNumbers(&A, &M, &K, NULL);
        sha.Finalize();

        SendProof(sha);

        ///- Set _authed to true!
        _authed = true;
    }
    else
    {
        if (_build > 6005)                                  // > 1.12.2
        {
            char data[4] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0};
            send(data, sizeof(data));
        }
        else
        {
            // 1.x not react incorrectly at 4-byte message use 3 as real error
            char data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT};
            send(data, sizeof(data));
        }
        BASIC_LOG("[AuthChallenge] account %s tried to login with wrong password!", _login.c_str());

        uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0);
        if (MaxWrongPassCount > 0)
        {
            // Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
            LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'", _safelogin.c_str());

            if (QueryResult* loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str()))
            {
                Field* fields = loginfail->Fetch();
                uint32 failed_logins = fields[1].GetUInt32();

                if (failed_logins >= MaxWrongPassCount)
                {
                    uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600);
                    bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false);

                    if (WrongPassBanType)
                    {
                        uint32 acc_id = fields[0].GetUInt32();
                        LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)",
                                               acc_id, WrongPassBanTime);
                        BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
                                  _login.c_str(), WrongPassBanTime, failed_logins);
                    }
                    else
                    {
                        std::string current_ip = get_remote_address();
                        LoginDatabase.escape_string(current_ip);
                        LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')",
                                               current_ip.c_str(), WrongPassBanTime);
                        BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times",
                                  current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
                    }
                }
                delete loginfail;
            }
        }
    }
    return true;
}
Exemplo n.º 30
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);
}