// 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); }
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); }
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; }
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; }
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; }
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; }
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()); } }
/// 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; }