示例#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();

    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SET_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);
}
示例#2
0
void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
{
    uint8 digest[SHA_DIGEST_LENGTH];
    uint32 clientSeed;
    uint8 security;
    uint32 id;
    LocaleConstant locale;
    std::string account;
    bool isPremium = false;
    SHA1Hash sha;
    uint32 clientBuild;
    uint32 serverId, loginServerType, region, battlegroup, realmIndex;
    uint64 unk4;
    WorldPacket packet, SendAddonPacked;
    BigNumber k;
    bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);

    // Read the content of the packet
    recvPacket >> clientBuild;
    recvPacket >> serverId;                 // Used for GRUNT only
    recvPacket >> account;
    recvPacket >> loginServerType;          // 0 GRUNT, 1 Battle.net
    recvPacket >> clientSeed;
    recvPacket >> region >> battlegroup;    // Used for Battle.net only
    recvPacket >> realmIndex;               // realmId from auth_database.realmlist table
    recvPacket >> unk4;
    recvPacket.read(digest, 20);

    TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, loginServerType %u, clientseed %u, realmIndex %u",
        clientBuild,
        serverId,
        account.c_str(),
        loginServerType,
        clientSeed,
        realmIndex);

    // Get the account information from the auth database
    //         0           1        2       3          4         5       6          7   8
    // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?
    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME);

    stmt->setString(0, account);

    PreparedQueryResult result = LoginDatabase.Query(stmt);

    // Stop if the account is not found
    if (!result)
    {
        // We can not log here, as we do not know the account. Thus, no accountId.
        SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT);
        TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
        DelayedCloseSocket();
        return;
    }

    Field* fields = result->Fetch();

    uint8 expansion = fields[4].GetUInt8();
    uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION);
    if (expansion > world_expansion)
        expansion = world_expansion;

    // For hook purposes, we get Remoteaddress at this point.
    std::string address = GetRemoteIpAddress().to_string();

    // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
    stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);

    stmt->setString(0, address);
    stmt->setString(1, account);

    LoginDatabase.Execute(stmt);
    // This also allows to check for possible "hack" attempts on account

    // id has to be fetched at this point, so that first actual account response that fails can be logged
    id = fields[0].GetUInt32();

    k.SetHexStr(fields[1].GetCString());

    // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
    _authCrypt.Init(&k);

    // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
    if (sWorld->IsClosed())
    {
        SendAuthResponseError(AUTH_REJECT);
        TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str());
        DelayedCloseSocket();
        return;
    }

    if (realmIndex != realmID)
    {
        SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND);
        TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm).");
        DelayedCloseSocket();
        return;
    }

    std::string os = fields[8].GetString();

    // Must be done before WorldSession is created
    if (wardenActive && os != "Win" && os != "OSX")
    {
        SendAuthResponseError(AUTH_REJECT);
        TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str());
        DelayedCloseSocket();
        return;
    }

    // Check that Key and account name are the same on client and server
    uint32 t = 0;

    sha.UpdateData(account);
    sha.UpdateData((uint8*)&t, 4);
    sha.UpdateData((uint8*)&clientSeed, 4);
    sha.UpdateData((uint8*)&_authSeed, 4);
    sha.UpdateBigNumbers(&k, NULL);
    sha.Finalize();

    if (memcmp(sha.GetDigest(), digest, SHA_DIGEST_LENGTH) != 0)
    {
        SendAuthResponseError(AUTH_FAILED);
        TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str());
        DelayedCloseSocket();
        return;
    }

    ///- Re-check ip locking (same check as in auth).
    if (fields[3].GetUInt8() == 1) // if ip is locked
    {
        if (strcmp(fields[2].GetCString(), address.c_str()) != 0)
        {
            SendAuthResponseError(AUTH_FAILED);
            TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str());
            // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
            sScriptMgr->OnFailedAccountLogin(id);
            DelayedCloseSocket();
            return;
        }
    }

    int64 mutetime = fields[5].GetInt64();
    //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
    if (mutetime < 0)
    {
        mutetime = time(NULL) + llabs(mutetime);

        PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);

        stmt->setInt64(0, mutetime);
        stmt->setUInt32(1, id);

        LoginDatabase.Execute(stmt);
    }

    locale = LocaleConstant(fields[6].GetUInt8());
    if (locale >= TOTAL_LOCALES)
        locale = LOCALE_enUS;

    uint32 recruiter = fields[7].GetUInt32();
    // Checks gmlevel per Realm
    stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID);

    stmt->setUInt32(0, id);
    stmt->setInt32(1, int32(realmID));

    result = LoginDatabase.Query(stmt);

    if (!result)
        security = 0;
    else
    {
        fields = result->Fetch();
        security = fields[0].GetUInt8();
    }

    // Re-check account ban (same check as in auth)
    stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BANS);

    stmt->setUInt32(0, id);
    stmt->setString(1, address);

    PreparedQueryResult banresult = LoginDatabase.Query(stmt);

    if (banresult) // if account banned
    {
        SendAuthResponseError(AUTH_BANNED);
        TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
        sScriptMgr->OnFailedAccountLogin(id);
        DelayedCloseSocket();
        return;
    }

    // Check premium
    stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PREMIUM);
    stmt->setUInt32(0, id);
    PreparedQueryResult premresult = LoginDatabase.Query(stmt);

    if (premresult)
    {
        isPremium = true;
    }

    // Check locked state for server
    AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
    TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security));
    if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
    {
        SendAuthResponseError(AUTH_UNAVAILABLE);
        TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
        sScriptMgr->OnFailedAccountLogin(id);
        DelayedCloseSocket();
        return;
    }

    TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
        account.c_str(),
        address.c_str());

    // Check if this user is by any chance a recruiter
    stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_RECRUITER);

    stmt->setUInt32(0, id);

    result = LoginDatabase.Query(stmt);

    bool isRecruiter = false;
    if (result)
        isRecruiter = true;

    // Update the last_ip in the database as it was successful for login
    stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);

    stmt->setString(0, address);
    stmt->setString(1, account);

    LoginDatabase.Execute(stmt);

    // At this point, we can safely hook a successful login
    sScriptMgr->OnAccountLogin(id);

    _authed = true;
    _worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), isPremium, expansion, mutetime, locale, recruiter, isRecruiter);
    _worldSession->LoadGlobalAccountData();
    _worldSession->LoadTutorialsData();
    _worldSession->ReadAddonsInfo(recvPacket);
    _worldSession->LoadPermissions();

    // Initialize Warden system only if it is enabled by config
    if (wardenActive)
        _worldSession->InitWarden(&k, os);

    sWorld->AddSession(_worldSession);
}
示例#3
0
int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
{
    // NOTE: ATM the socket is singlethread, have this in mind ...
    uint8 digest[20];
    uint32 clientSeed;
    uint32 unk2;
    uint32 BuiltNumberClient;
    uint32 id, security;
    uint8 expansion = 0;
    LocaleConstant locale;
    std::string account;
    Sha1Hash sha1;
    BigNumber v, s, g, N, x, I;
    WorldPacket packet, SendAddonPacked;

    BigNumber K;

    if (recvPacket.size () < (4 + 4 + 1 + 4 + 20))
    {
        sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size");
        return -1;
    }

    // Read the content of the packet
    recvPacket >> BuiltNumberClient;                        // for now no use
    recvPacket >> unk2;
    recvPacket >> account;

    if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20))
    {
        sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check");
        return -1;
    }

    recvPacket >> clientSeed;
    recvPacket.read (digest, 20);

    DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
                BuiltNumberClient,
                unk2,
                account.c_str (),
                clientSeed);

    // Get the account information from the realmd database
    std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
    loginDatabase.escape_string (safe_account);
    // No SQL injection, username escaped.

    QueryResult *result =
          loginDatabase.PQuery ("SELECT "
                                "id, " //0
                                "gmlevel, " //1
                                "sessionkey, " //2
                                "last_ip, " //3
                                "locked, " //4
                                "sha_pass_hash, " //5
                                "v, " //6
                                "s, " //7
                                "expansion, " //8
                                "mutetime, " //9
                                "locale " //10
                                "FROM account "
                                "WHERE username = '******'",
                                safe_account.c_str ());

    // Stop if the account is not found
    if (!result)
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_UNKNOWN_ACCOUNT);

        SendPacket (packet);

        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
        return -1;
    }

    Field* fields = result->Fetch ();

    expansion = fields[8].GetUInt8 () && sWorld.getConfig (CONFIG_EXPANSION) > 0;

    N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
    g.SetDword (7);
    I.SetHexStr (fields[5].GetString ());

    //In case of leading zeros in the I 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);

    s.SetHexStr (fields[7].GetString ());
    sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ());
    sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH);
    sha1.Finalize ();
    x.SetBinary (sha1.GetDigest (), sha1.GetLength ());
    v = g.ModExp (x, N);

    const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free()
    const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free()
    const char* vold = fields[6].GetString ();

    DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s",
                sStr,
                vold,
                vStr);

    loginDatabase.PExecute ("UPDATE account "
                            "SET "
                            "v = '0', "
                            "s = '0' "
                            "WHERE username = '******'",
                            safe_account.c_str ());

    if (!vold || strcmp (vStr, vold))
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_UNKNOWN_ACCOUNT);
        SendPacket (packet);
        delete result;
        OPENSSL_free ((void*) sStr);
        OPENSSL_free ((void*) vStr);

        sLog.outBasic ("WorldSocket::HandleAuthSession: User not logged.");
        return -1;
    }

    OPENSSL_free ((void*) sStr);
    OPENSSL_free ((void*) vStr);

    ///- Re-check ip locking (same check as in realmd).
    if (fields[4].GetUInt8 () == 1) // if ip is locked
    {
        if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ()))
        {
            packet.Initialize (SMSG_AUTH_RESPONSE, 1);
            packet << uint8 (AUTH_FAILED);
            SendPacket (packet);

            delete result;
            sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
            return -1;
        }
    }

    id = fields[0].GetUInt32 ();
    security = fields[1].GetUInt16 ();
    K.SetHexStr (fields[2].GetString ());

    time_t mutetime = time_t (fields[9].GetUInt64 ());

    locale = LocaleConstant (fields[10].GetUInt8 ());
    if (locale >= MAX_LOCALE)
        locale = LOCALE_enUS;

    delete result;

    // Re-check account ban (same check as in realmd)
    QueryResult *banresult =
          loginDatabase.PQuery ("SELECT "
                                "bandate, "
                                "unbandate "
                                "FROM account_banned "
                                "WHERE id = '%u' "
                                "AND active = 1",
                                id);

    if (banresult) // if account banned
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_BANNED);
        SendPacket (packet);

        delete banresult;

        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
        return -1;
    }

    // Check locked state for server
    AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit ();

    if (allowedAccountType > SEC_PLAYER && security < allowedAccountType)
    {
        WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
        Packet << uint8 (AUTH_UNAVAILABLE);

        SendPacket (packet);

        sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough");
        return -1;
    }

    // Check that Key and account name are the same on client and server
    Sha1Hash sha;

    uint32 t = 0;
    uint32 seed = m_Seed;

    sha.UpdateData (account);
    sha.UpdateData ((uint8 *) & t, 4);
    sha.UpdateData ((uint8 *) & clientSeed, 4);
    sha.UpdateData ((uint8 *) & seed, 4);
    sha.UpdateBigNumbers (&K, NULL);
    sha.Finalize ();

    if (memcmp (sha.GetDigest (), digest, 20))
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_FAILED);

        SendPacket (packet);

        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
        return -1;
    }

    std::string address = GetRemoteAddress ();

    DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
                account.c_str (),
                address.c_str ());

    // Update the last_ip in the database
    // No SQL injection, username escaped.
    loginDatabase.escape_string (address);

    loginDatabase.PExecute ("UPDATE account "
                            "SET last_ip = '%s' "
                            "WHERE username = '******'",
                            address.c_str (),
                            safe_account.c_str ());

    // NOTE ATM the socket is singlethreaded, have this in mind ...
    ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1);

    m_Crypt.SetKey (&K);
    m_Crypt.Init ();

    // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec
    ACE_OS::sleep (ACE_Time_Value (0, 10000));

    sWorld.AddSession (m_Session);

    // Create and send the Addon packet
    if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked))
        SendPacket (SendAddonPacked);

    return 0;
}
示例#4
0
int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
{
    // NOTE: ATM the socket is singlethread, have this in mind ...
    uint8 digest[20];
    uint32 clientSeed;
    uint32 unk2;
    uint32 BuiltNumberClient;
    uint32 id, security;
    //uint8 expansion = 0;
    LocaleConstant locale;
    std::string account;
    Sha1Hash sha1;
    BigNumber v, s, g, N;
    WorldPacket packet, SendAddonPacked;

    BigNumber K;

    // Read the content of the packet
    recvPacket >> BuiltNumberClient;
    recvPacket >> unk2;
    recvPacket >> account;

    recvPacket >> clientSeed;
    recvPacket.read (digest, 20);

    DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",
               BuiltNumberClient,
               unk2,
               account.c_str (),
               clientSeed);

    // Check the version of client trying to connect
    if (!IsAcceptableClientBuild(BuiltNumberClient))
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_VERSION_MISMATCH);

        SendPacket (packet);

        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch).");
        return -1;
    }

    // Get the account information from the realmd database
    std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
    LoginDatabase.escape_string (safe_account);
    // No SQL injection, username escaped.

    QueryResult_AutoPtr result = LoginDatabase.PQuery ("SELECT "
                                 "id, "                      //0
                                 "gmlevel, "                 //1
                                 "sessionkey, "              //2
                                 "last_ip, "                 //3
                                 "locked, "                  //4
                                 "v, "                       //5
                                 "s, "                       //6
                                 "expansion, "               //7
                                 "mutetime, "                //8
                                 "locale "                   //9
                                 "FROM account "
                                 "WHERE username = '******'",
                                 safe_account.c_str ());

    // Stop if the account is not found
    if (!result)
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_UNKNOWN_ACCOUNT);

        SendPacket (packet);

        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
        return -1;
    }

    Field* fields = result->Fetch ();

    uint8 expansion = fields[7].GetUInt8();
    uint32 world_expansion = sWorld.getConfig(CONFIG_EXPANSION);
    if (expansion > world_expansion)
        expansion = world_expansion;
    //expansion = ((sWorld.getConfig(CONFIG_EXPANSION) > fields[7].GetUInt8()) ? fields[7].GetUInt8() : sWorld.getConfig(CONFIG_EXPANSION));

    N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
    g.SetDword (7);

    v.SetHexStr(fields[5].GetString());
    s.SetHexStr (fields[6].GetString ());

    const char* sStr = s.AsHexStr ();                       //Must be freed by OPENSSL_free()
    const char* vStr = v.AsHexStr ();                       //Must be freed by OPENSSL_free()

    DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v: %s",
               sStr,
               vStr);

    OPENSSL_free ((void*) sStr);
    OPENSSL_free ((void*) vStr);

    // Re-check ip locking (same check as in realmd).
    if (fields[4].GetUInt8 () == 1) // if ip is locked
    {
        if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ()))
        {
            packet.Initialize (SMSG_AUTH_RESPONSE, 1);
            packet << uint8 (AUTH_FAILED);
            SendPacket (packet);

            sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
            return -1;
        }
    }

    id = fields[0].GetUInt32 ();
    security = fields[1].GetUInt16 ();
    K.SetHexStr (fields[2].GetString ());

    time_t mutetime = time_t (fields[8].GetUInt64 ());

    locale = LocaleConstant (fields[9].GetUInt8 ());
    if (locale >= MAX_LOCALE)
        locale = LOCALE_enUS;

    // Re-check account ban (same check as in realmd)
    QueryResult_AutoPtr banresult = LoginDatabase.PQuery ("SELECT "
                                    "bandate, "
                                    "unbandate "
                                    "FROM account_banned "
                                    "WHERE id = '%u' "
                                    "AND active = 1",
                                    id);

    if (banresult) // if account banned
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_BANNED);
        SendPacket (packet);

        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
        return -1;
    }

    // Check locked state for server
    sWorld.UpdateAllowedSecurity();
    AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit ();
    sLog.outDebug("Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security));
    if (allowedAccountType > SEC_PLAYER && security < allowedAccountType)
    {
        WorldPacket Packet (SMSG_AUTH_RESPONSE, 1);
        Packet << uint8 (AUTH_UNAVAILABLE);

        SendPacket (packet);

        sLog.outDetail ("WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
        return -1;
    }

    // Check that Key and account name are the same on client and server
    Sha1Hash sha;

    uint32 t = 0;
    uint32 seed = m_Seed;

    sha.UpdateData (account);
    sha.UpdateData ((uint8 *) & t, 4);
    sha.UpdateData ((uint8 *) & clientSeed, 4);
    sha.UpdateData ((uint8 *) & seed, 4);
    sha.UpdateBigNumbers (&K, NULL);
    sha.Finalize ();

    if (memcmp (sha.GetDigest (), digest, 20))
    {
        packet.Initialize (SMSG_AUTH_RESPONSE, 1);
        packet << uint8 (AUTH_FAILED);

        SendPacket (packet);

        sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed).");
        return -1;
    }

    std::string address = GetRemoteAddress();

    DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
               account.c_str(),
               address.c_str());

    // Update the last_ip in the database
    // No SQL injection, username escaped.
    LoginDatabase.escape_string (address);

    LoginDatabase.PExecute ("UPDATE account "
                            "SET last_ip = '%s' "
                            "WHERE username = '******'",
                            address.c_str(),
                            safe_account.c_str());

    // NOTE ATM the socket is single-threaded, have this in mind ...
    ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1);

    m_Crypt.SetKey(&K);
    m_Crypt.Init();

    // Sleep this Network thread for
    uint32 sleepTime = sWorld.getConfig(CONFIG_SESSION_ADD_DELAY);
    ACE_OS::sleep(ACE_Time_Value (0, sleepTime));

    sWorld.AddSession (m_Session);

    // Create and send the Addon packet
    if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked))
        SendPacket(SendAddonPacked);

    return 0;
}
示例#5
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;
}
示例#6
0
void AccountMgr::AddAccount(Field* field)
{
    Account* acct = new Account;
    Sha1Hash hash;
    std::string Username     = field[1].GetString();
    std::string EncryptedPassword = field[2].GetString();

    acct->AccountId                = field[0].GetUInt32();
    acct->AccountFlags            = field[3].GetUInt8();
    acct->Banned                = field[4].GetUInt32();
    if((uint32)UNIXTIME > acct->Banned && acct->Banned != 0 && acct->Banned != 1)   //1 = perm ban?
    {
        acct->Banned = 0;
        sLogonSQL->Execute("UPDATE accounts SET banned = 0 WHERE id = %u", acct->AccountId);
    }
    acct->Locale[0] = 'e';
    acct->Locale[1] = 'n';
    acct->Locale[2] = 'U';
    acct->Locale[3] = 'S';
    if(strcmp(field[5].GetString(), "enUS"))
    {
        // non-standard language forced
        memcpy(acct->Locale, field[5].GetString(), 4);
        acct->forcedLocale = true;
    }
    else
        acct->forcedLocale = false;

    acct->Muted = field[6].GetUInt32();
    if((uint32)UNIXTIME > acct->Muted && acct->Muted != 0 && acct->Muted != 1)   //1 = perm ban?
    {
        acct->Muted = 0;
        sLogonSQL->Execute("UPDATE accounts SET muted = 0 WHERE id = %u", acct->AccountId);
    }
    // Convert username to uppercase. this is needed ;)
    Util::StringToUpperCase(Username);

    // prefer encrypted passwords over nonencrypted
    if(EncryptedPassword.size() > 0)
    {
        if(EncryptedPassword.size() == 40)
        {
            BigNumber bn;
            bn.SetHexStr(EncryptedPassword.c_str());
            if(bn.GetNumBytes() < 20)
            {
                // Hacky fix
                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
        {
            LOG_ERROR("Account `%s` has incorrect number of bytes in encrypted password! Disabling.", Username.c_str());
            memset(acct->SrpHash, 0, 20);
        }
    }
    else
    {
        // This should never happen...
        LOG_ERROR("Account `%s` has no encrypted password!", Username.c_str());
    }

    AccountDatabase[Username] = acct;
}
示例#7
0
void AccountMgr::UpdateAccount(Account* acct, Field* field)
{
    uint32 id = field[0].GetUInt32();
    Sha1Hash hash;
    std::string Username     = field[1].GetString();
    std::string EncryptedPassword = field[2].GetString();

    if(id != acct->AccountId)
    {
        LOG_ERROR(" >> deleting duplicate account %u [%s]...", id, Username.c_str());
        sLogonSQL->Execute("DELETE FROM accounts WHERE id = %u", id);
        return;
    }

    acct->AccountId                = field[0].GetUInt32();
    acct->AccountFlags            = field[3].GetUInt8();
    acct->Banned                = field[4].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;
        LOG_DEBUG("Account %s's ban has expired.", acct->UsernamePtr->c_str());
        sLogonSQL->Execute("UPDATE accounts SET banned = 0 WHERE id = %u", acct->AccountId);
    }
    if(strcmp(field[5].GetString(), "enUS"))
    {
        // non-standard language forced
        memcpy(acct->Locale, field[5].GetString(), 4);
        acct->forcedLocale = true;
    }
    else
        acct->forcedLocale = false;

    acct->Muted = field[6].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;
        LOG_DEBUG("Account %s's mute has expired.", acct->UsernamePtr->c_str());
        sLogonSQL->Execute("UPDATE accounts SET muted = 0 WHERE id = %u", acct->AccountId);
    }
    // Convert username to uppercase. this is needed ;)
    Util::StringToUpperCase(Username);

    // prefer encrypted passwords over nonencrypted
    if(EncryptedPassword.size() > 0)
    {
        if(EncryptedPassword.size() == 40)
        {
            BigNumber bn;
            bn.SetHexStr(EncryptedPassword.c_str());
            if(bn.GetNumBytes() < 20)
            {
                // Hacky fix
                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
        {
            LOG_ERROR("Account `%s` has incorrect number of bytes in encrypted password! Disabling.", Username.c_str());
            memset(acct->SrpHash, 0, 20);
        }
    }
    else
    {
        // This should never happen...
        LOG_ERROR("Account `%s` has no encrypted password!", Username.c_str());
    }
}
示例#8
0
/// Handle the client authentication packet
void WorldSocket::_HandleAuthSession(WorldPacket& recvPacket)
{
    uint8 digest[20];
    uint32 clientSeed;
    uint32 unk2;
    uint32 BuiltNumberClient;
    uint32 id, security;
    std::string account;
    Sha1Hash I;
    Sha1Hash sha1;
    BigNumber v, s, g, N, x;
    std::string password;
    WorldPacket packet, SendAddonPacked;

    BigNumber K;

    ///- Read the content of the packet
    try
    {
        recvPacket >> BuiltNumberClient;                    // for now no use
        recvPacket >> unk2;
        recvPacket >> account;
        recvPacket >> clientSeed;
        recvPacket.read(digest, 20);
    }
    catch(ByteBuffer::error &)
    {
        sLog.outError("WorldSocket::_HandleAuthSession Get Incomplete packet");
        return;
    }
    sLog.outDebug("Auth: client %u, unk2 %u, account %s, clientseed %u", BuiltNumberClient, unk2, account.c_str(), clientSeed);

    ///- Get the account information from the realmd database
    std::string safe_account=account;                       // Duplicate, else will screw the SHA hash verification below
    loginDatabase.escape_string(safe_account);
    //No SQL injection, username escaped.
    QueryResult *result = loginDatabase.PQuery("SELECT `id`,`gmlevel`,`sessionkey`,`last_ip`,`locked`, `password`, `v`, `s`, `banned` FROM `account` WHERE `username` = '%s'", safe_account.c_str());

    ///- Stop if the account is not found
    if ( !result )
    {
        packet.Initialize( SMSG_AUTH_RESPONSE, 1 );
        packet << uint8( AUTH_UNKNOWN_ACCOUNT );
        SendPacket( &packet );
        sLog.outDetail( "SOCKET: Sent Auth Response (unknown account)." );
        return;
    }

    N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
    g.SetDword(7);
    password = (*result)[5].GetString();
    std::transform(password.begin(), password.end(), password.begin(), std::towupper);

    s.SetHexStr((*result)[7].GetString());
    std::string sI = account + ":" + password;
    I.UpdateData(sI);
    I.Finalize();
    sha1.UpdateData(s.AsByteArray(), s.GetNumBytes());
    sha1.UpdateData(I.GetDigest(), 20);
    sha1.Finalize();
    x.SetBinary(sha1.GetDigest(), sha1.GetLength());
    v = g.ModExp(x, N);

    sLog.outDebug("SOCKET: (s,v) check s: %s v_old: %s v_new: %s", s.AsHexStr(), (*result)[6].GetString(), v.AsHexStr() );
    loginDatabase.PQuery("UPDATE `account` SET `v` = '0', `s` = '0' WHERE `username` = '%s'", safe_account.c_str());
    if ( strcmp(v.AsHexStr(),(*result)[6].GetString() ) )
    {
        packet.Initialize( SMSG_AUTH_RESPONSE, 1 );
        packet << uint8( AUTH_UNKNOWN_ACCOUNT );
        SendPacket( &packet );
        sLog.outDetail( "SOCKET: User not logged.");
        delete result;
        return;
    }

    ///- Re-check ip locking (same check as in realmd).
    if((*result)[4].GetUInt8() == 1)                        // if ip is locked
    {
        if ( strcmp((*result)[3].GetString(),GetRemoteAddress().c_str()) )
        {
            packet.Initialize( SMSG_AUTH_RESPONSE, 1 );
            packet << uint8( REALM_AUTH_ACCOUNT_FREEZED );
            SendPacket( &packet );

            sLog.outDetail( "SOCKET: Sent Auth Response (Account IP differs)." );
            delete result;
            return;
        }
    }

    ///- Re-check account ban (same check as in realmd).
    if((*result)[8].GetUInt8() == 1)                        // if account banned
    {
        packet.Initialize( SMSG_AUTH_RESPONSE, 1 );
        packet << uint8( AUTH_BANNED );
        SendPacket( &packet );

        sLog.outDetail( "SOCKET: Sent Auth Response (Account banned)." );
        delete result;
        return;
    }

    id = (*result)[0].GetUInt32();
    security = (*result)[1].GetUInt16();
    K.SetHexStr((*result)[2].GetString());

    delete result;

    ///- Check that we do not exceed the maximum number of online players in the realm
    uint32 num = sWorld.GetSessionCount();
    if (sWorld.GetPlayerLimit() > 0 && num >= sWorld.GetPlayerLimit() && security == 0)
    {
        /// \todo Handle the waiting queue when the server is full
        SendAuthWaitQue(1);
        sLog.outDetail( "SOCKET: Sent Auth Response (server queue)." );
        return;
    }

    ///- kick already loaded player with same account (if any) and remove session
    ///- if player is in loading and want to load again, return
    if(!sWorld.RemoveSession(id))
    {
        return;
    }

    ///- Check that Key and account name are the same on client and server
    Sha1Hash sha;

    uint32 t = 0;
    uint32 seed = _seed;

    sha.UpdateData(account);
    sha.UpdateData((uint8 *)&t, 4);
    sha.UpdateData((uint8 *)&clientSeed, 4);
    sha.UpdateData((uint8 *)&seed, 4);
    sha.UpdateBigNumbers(&K, NULL);
    sha.Finalize();

    if (memcmp(sha.GetDigest(), digest, 20))
    {
        packet.Initialize( SMSG_AUTH_RESPONSE, 1 );
        packet << uint8( AUTH_FAILED );

        SendPacket( &packet );

        sLog.outDetail( "SOCKET: Sent Auth Response (authentification failed)." );
        return;
    }

    ///- Initialize the encryption with the Key
    _crypt.SetKey(K.AsByteArray(), 40);
    _crypt.Init();

    ///- Send 'Auth is ok'
    packet.Initialize( SMSG_AUTH_RESPONSE, 1+4+1+4 );
    packet << uint8( AUTH_OK );
    packet << (uint32)0; // unknown random value...
    packet << (uint8)2;
    packet << (uint32)0;
    SendPacket(&packet);

    ///- Create a new WorldSession for the player and add it to the World
    _session = new WorldSession(id, this,security);
    sWorld.AddSession(_session);

    sLog.outDebug( "SOCKET: Client '%s' authenticated successfully.", account.c_str() );
    sLog.outDebug( "Account: '%s' Logged in from IP %s.", account.c_str(), GetRemoteAddress().c_str());

    ///- Update the last_ip in the database
    //No SQL injection, username escaped.
    loginDatabase.PQuery("UPDATE `account` SET `last_ip` = '%s' WHERE `username` = '%s'",GetRemoteAddress().c_str(), safe_account.c_str());

    // do small delay (10ms) at accepting successful authed connection to prevent droping packets by client
    // don't must harm anyone (let login ~100 accounts in 1 sec ;) )
    #ifdef WIN32
    Sleep(10);
    #endif

    ///- Create and send the Addon packet
    if(sAddOnHandler.BuildAddonPacket(&recvPacket, &SendAddonPacked, recvPacket.rpos()))
        SendPacket(&SendAddonPacked);

    return;
}
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[4].GetString();

	acct->AccountId				= field[0].GetUInt32();
	acct->AccountFlags			= field[5].GetUInt8();
	acct->Banned				= field[6].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[7].GetString(), "enUS"))
	{
		// non-standard language forced
		memcpy(acct->Locale, field[7].GetString(), 4);
		acct->forcedLocale = true;
	}
	else
		acct->forcedLocale = false;

    acct->Muted = field[8].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;
		//sLog.outDebug("Account %s's mute has expired.",acct->UsernamePtr->c_str());
		sLogonSQL->Execute("UPDATE accounts SET muted = 0 WHERE acct=%u",acct->AccountId);
	}
	// Convert username/password to uppercase. this is needed ;)
	ASCENT_TOUPPER(Username);
	ASCENT_TOUPPER(Password);
	
	if( EncryptedPassword.size() > 0 )
	{
		// prefer encrypted passwords over nonencrypted
		BigNumber bn;
		bn.SetHexStr( EncryptedPassword.c_str() );
		if( bn.GetNumBytes() != 20 )
		{
			printf("Account `%s` has incorrect number of bytes (%u) in encrypted password! Disabling.\n", Username.c_str(), bn.GetNumBytes());
			memset(acct->SrpHash, 0, 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;
}