예제 #1
0
bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response)
{
    TC_LOG_ERROR("session.packets", "Unhandled module.");
    Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
    logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
    ReplaceResponse(response, logonResponse);
    return false;
}
예제 #2
0
bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response)
{
    Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
    if (dataStream->Read<uint8>(8) == 1)
    {
        logonResponse->AccountId = _accountId;
        logonResponse->GameAccountName = _gameAccountName;
        logonResponse->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK;
        PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_FAILED_LOGINS);
        stmt->setUInt32(0, _accountId);
        if (PreparedQueryResult failedLoginsResult = LoginDatabase.Query(stmt))
            logonResponse->FailedLogins = (*failedLoginsResult)[0].GetUInt32();

        SQLTransaction trans = LoginDatabase.BeginTransaction();

        stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO);
        stmt->setString(0, GetRemoteIpAddress().to_string());
        stmt->setUInt8(1, GetLocaleByName(_locale));
        stmt->setString(2, _os);
        stmt->setUInt32(3, _accountId);
        trans->Append(stmt);

        stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
        stmt->setString(0, K.AsHexStr());
        stmt->setBool(1, true);
        stmt->setUInt32(2, _accountId);
        trans->Append(stmt);

        LoginDatabase.CommitTransaction(trans);

        _authed = true;
        sSessionMgr.AddSession(this);
    }
    else
        logonResponse->SetAuthResult(AUTH_BAD_VERSION_HASH);

    ReplaceResponse(response, logonResponse);
    return true;
}
예제 #3
0
bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response)
{
    if (dataStream->Read<uint8>(8) != 1)
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
        ReplaceResponse(response, logonResponse);
        return false;
    }

    dataStream->Read<uint8>(8);
    std::string account = dataStream->ReadString(8);
    if (account.empty())
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
        ReplaceResponse(response, logonResponse);
        return false;
    }

    for (std::size_t i = 0; i < _gameAccounts.size(); ++i)
    {
        if (_gameAccounts[i].DisplayName == account)
        {
            _gameAccountInfo = &_gameAccounts[i];
            break;
        }
    }

    if (!_gameAccountInfo)
    {
        Authentication::LogonResponse* complete = new Authentication::LogonResponse();
        complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
        ReplaceResponse(response, complete);
        TC_LOG_DEBUG("session", "[Battlenet::SelectGameAccount] %s attempted to log in with invalid game account name %s!", GetClientInfo().c_str(), account.c_str());
        return false;
    }

    if (_gameAccountInfo->IsBanned)
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        if (_gameAccountInfo->IsPermanentlyBanned)
        {
            logonResponse->SetAuthResult(LOGIN_BANNED);
            TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] 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::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str());
        }

        ReplaceResponse(response, logonResponse);
        return false;
    }

    Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest();
    proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint"));
    ReplaceResponse(response, proofRequest);

    _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT);
    return true;
}
예제 #4
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;
}
예제 #5
0
bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket** response)
{
    if (dataStream->Read<uint8>(8) != 1)
    {
        Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
        resumeResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
        ReplaceResponse(response, resumeResponse);
        return false;
    }

    static uint8 const ResumeClient = 0;
    static uint8 const ResumeServer = 1;

    std::unique_ptr<uint8[]> clientChallenge = dataStream->ReadBytes(16);
    std::unique_ptr<uint8[]> clientProof = dataStream->ReadBytes(32);
    std::unique_ptr<uint8[]> serverChallenge = _reconnectProof.AsByteArray(16);
    std::unique_ptr<uint8[]> sessionKey = K.AsByteArray(64);

    HmacSha256 clientPart(64, sessionKey.get());
    clientPart.UpdateData(&ResumeClient, 1);
    clientPart.UpdateData(clientChallenge.get(), 16);
    clientPart.UpdateData(serverChallenge.get(), 16);
    clientPart.Finalize();

    HmacSha256 serverPart(64, sessionKey.get());
    serverPart.UpdateData(&ResumeServer, 1);
    serverPart.UpdateData(serverChallenge.get(), 16);
    serverPart.UpdateData(clientChallenge.get(), 16);
    serverPart.Finalize();

    uint8 newSessionKey[64];
    memcpy(&newSessionKey[0], clientPart.GetDigest(), clientPart.GetLength());
    memcpy(&newSessionKey[32], serverPart.GetDigest(), serverPart.GetLength());

    K.SetBinary(newSessionKey, 64);

    HmacSha256 proof(64, newSessionKey);
    proof.UpdateData(&ResumeClient, 1);
    proof.UpdateData(clientChallenge.get(), 16);
    proof.UpdateData(serverChallenge.get(), 16);
    proof.Finalize();

    if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength()))
    {
        PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS);
        stmt->setString(0, _accountInfo->Login);
        LoginDatabase.Execute(stmt);

        TC_LOG_DEBUG("session", "[Battlenet::Resume] %s attempted to reconnect with invalid password!", GetClientInfo().c_str());
        Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
        resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
        ReplaceResponse(response, resumeResponse);
        return false;
    }

    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY);
    stmt->setString(0, K.AsHexStr());
    stmt->setBool(1, true);
    stmt->setUInt32(2, _accountInfo->Id);
    LoginDatabase.Execute(stmt);

    HmacSha256 serverProof(64, newSessionKey);
    serverProof.UpdateData(&ResumeServer, 1);
    serverProof.UpdateData(serverChallenge.get(), 16);
    serverProof.UpdateData(clientChallenge.get(), 16);
    serverProof.Finalize();

    ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume");

    BitStream resumeData;
    uint8 state = 2;
    resumeData.WriteBytes(&state, 1);
    resumeData.WriteBytes(serverProof.GetDigest(), serverProof.GetLength());

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

    Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
    resumeResponse->Modules.push_back(resume);
    ReplaceResponse(response, resumeResponse);
    _authed = true;
    sSessionMgr.AddSession(this);
    return true;
}
예제 #6
0
bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response)
{
    if (dataStream->Read<uint8>(8) != 1)
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
        ReplaceResponse(response, logonResponse);
        return false;
    }

    dataStream->Read<uint8>(8);
    std::string account = dataStream->ReadString(8);
    if (account.empty())
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
        ReplaceResponse(response, logonResponse);
        return false;
    }

    PreparedStatement* stmt;
    if (account.substr(0, 3) != "WoW")
    {
        stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT);
        stmt->setString(0, account);
    }
    else
    {
        stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED);
        stmt->setUInt8(0, atol(account.substr(3).c_str()));
    }

    stmt->setUInt32(1, _accountId);
    PreparedQueryResult result = LoginDatabase.Query(stmt);
    if (!result)
    {
        Authentication::LogonResponse* complete = new Authentication::LogonResponse();
        complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
        ReplaceResponse(response, complete);
        TC_LOG_DEBUG("session", "[Battlenet::SelectGameAccount] %s attempted to log in with invalid game account name %s!", GetClientInfo().c_str(), account.c_str());
        return false;
    }

    Field* fields = result->Fetch();
    if (fields[4].GetBool())
    {
        Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
        if (fields[2].GetUInt32() == fields[3].GetUInt32())
        {
            logonResponse->SetAuthResult(LOGIN_BANNED);
            TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str());
        }
        else
        {
            logonResponse->SetAuthResult(LOGIN_SUSPENDED);
            TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str());
        }

        ReplaceResponse(response, logonResponse);
        return false;
    }

    _gameAccountId = fields[0].GetUInt32();
    _gameAccountName = fields[1].GetString();

    Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest();
    proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint"));
    ReplaceResponse(response, proofRequest);

    _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT);
    return true;
}