/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char*)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C*)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; // No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C* ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char*)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; ///- Normalize account name // utf8ToUpperOnlyLatin(_login); -- client already send account in expected form // Escape the user login to avoid further SQL injection // Memory will be freed on AuthSocket object destruction _safelogin = _login; LoginDatabase.escape_string(_safelogin); pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::string address = get_remote_address(); LoginDatabase.escape_string(address); QueryResult* result = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " // permanent still banned "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", address.c_str()); if (result) { pkt << (uint8)WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); delete result; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) result = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'", _safelogin.c_str()); if (result) { ///- If the IP is 'locked', check that the player comes indeed from the correct IP address bool locked = false; if ((*result)[2].GetUInt8() == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if (strcmp((*result)[3].GetString(), get_remote_address().c_str())) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) WOW_FAIL_SUSPENDED; locked = true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!locked) { ///- If the account is banned, reject the logon attempt QueryResult* banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE " "id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)", (*result)[1].GetUInt32()); if (banresult) { if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << (uint8) WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned account %s tries to login!", _login.c_str()); } else { pkt << (uint8) WOW_FAIL_SUSPENDED; BASIC_LOG("[AuthChallenge] Temporarily banned account %s tries to login!", _login.c_str()); } delete banresult; } else { ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = (*result)[0].GetCppString(); ///- Don't calculate (v, s) if there are already some in the database std::string databaseV = (*result)[5].GetCppString(); std::string databaseS = (*result)[6].GetCppString(); DEBUG_LOG("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2, bytes are stored as hexstring if (databaseV.size() != s_BYTE_SIZE * 2 || databaseS.size() != s_BYTE_SIZE * 2) _SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; MANGOS_ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); ///- Fill the response packet with the result pkt << uint8(WOW_SUCCESS); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if (securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if (securityFlags & 0x04) // Security token input { pkt << uint8(1); } uint8 secLevel = (*result)[4].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4 - i - 1]; BASIC_LOG("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str(), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); } } delete result; } else // no account { pkt << (uint8) WOW_FAIL_UNKNOWN_ACCOUNT; } } send((char const*)pkt.contents(), pkt.size()); return true; }
/// Logon Proof command handler bool AuthSocket::_HandleLogonProof() { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet sAuthLogonProof_C lp; if (!recv((char*)&lp, sizeof(sAuthLogonProof_C))) return false; ///- Check if the client has one of the expected version numbers bool valid_version = FindBuildInfo(_build) != NULL; /// <ul><li> If the client has no valid version if (!valid_version) { if (this->patch_ != ACE_INVALID_HANDLE) return false; ///- Check if we have the apropriate patch on the disk // file looks like: 65535enGB.mpq char tmp[64]; snprintf(tmp, 24, "./patches/%d%s.mpq", _build, _localizationName.c_str()); char filename[PATH_MAX]; if (ACE_OS::realpath(tmp, filename) != NULL) { patch_ = ACE_OS::open(filename, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN); } if (patch_ == ACE_INVALID_HANDLE) { // no patch found ByteBuffer pkt; pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; pkt << (uint8) WOW_FAIL_VERSION_INVALID; DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); send((char const*)pkt.contents(), pkt.size()); return true; } XFER_INIT xferh; ACE_OFF_T file_size = ACE_OS::filesize(this->patch_); if (file_size == -1) { close_connection(); return false; } if (!PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5)) { // calculate patch md5, happens if patch was added while realmd was running PatchCache::instance()->LoadPatchMD5(tmp); PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5); } uint8 data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE}; send((const char*)data, sizeof(data)); memcpy(&xferh, "0\x05Patch", 7); xferh.cmd = CMD_XFER_INITIATE; xferh.file_size = file_size; send((const char*)&xferh, sizeof(xferh)); return true; } /// </ul> ///- Continue the SRP6 calculation based on data received from the client BigNumber A; A.SetBinary(lp.A, 32); // SRP safeguard: abort if A==0 if (A.isZero()) return false; Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), 20); BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); uint8 t[32]; uint8 t1[16]; uint8 vK[40]; memcpy(t, S.AsByteArray(32), 32); for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2] = sha.GetDigest()[i]; } for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2 + 1]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2 + 1] = sha.GetDigest()[i]; } K.SetBinary(vK, 40); uint8 hash[20]; sha.Initialize(); sha.UpdateBigNumbers(&N, NULL); sha.Finalize(); memcpy(hash, sha.GetDigest(), 20); sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); for (int i = 0; i < 20; ++i) { hash[i] ^= sha.GetDigest()[i]; } BigNumber t3; t3.SetBinary(hash, 20); sha.Initialize(); sha.UpdateData(_login); sha.Finalize(); uint8 t4[SHA_DIGEST_LENGTH]; memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); sha.Initialize(); sha.UpdateBigNumbers(&t3, NULL); sha.UpdateData(t4, SHA_DIGEST_LENGTH); sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); BigNumber M; M.SetBinary(sha.GetDigest(), 20); ///- Check if SRP6 results match (password is correct), else send an error if (!memcmp(M.AsByteArray(), lp.M1, 20)) { BASIC_LOG("User '%s' successfully authenticated", _login.c_str()); ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket const char* K_hex = K.AsHexStr(); LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, get_remote_address().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str()); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); sha.Finalize(); SendProof(sha); ///- Set _authed to true! _authed = true; } else { if (_build > 6005) // > 1.12.2 { char data[4] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; send(data, sizeof(data)); } else { // 1.x not react incorrectly at 4-byte message use 3 as real error char data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT}; send(data, sizeof(data)); } BASIC_LOG("[AuthChallenge] account %s tried to login with wrong password!", _login.c_str()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); if (MaxWrongPassCount > 0) { // Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'", _safelogin.c_str()); if (QueryResult* loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str())) { Field* fields = loginfail->Fetch(); uint32 failed_logins = fields[1].GetUInt32(); if (failed_logins >= MaxWrongPassCount) { uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600); bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false); if (WrongPassBanType) { uint32 acc_id = fields[0].GetUInt32(); LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); } else { std::string current_ip = get_remote_address(); LoginDatabase.escape_string(current_ip); LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); } } delete loginfail; } } } return true; }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; _os = (const char*)ch->os; if(_os.size() > 4) return false; ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; LoginDatabase.escape_string(_safelogin); // Starting CMD_AUTH_LOGON_CHALLENGE AuthResult result = WOW_FAIL_UNKNOWN0; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::string address = get_remote_address(); LoginDatabase.escape_string(address); QueryResult* qresult = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " // permanent still banned "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", address.c_str()); if (qresult) { result = WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); delete qresult; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) qresult = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'",_safelogin.c_str()); if (qresult) { ///- If the IP is 'locked', check that the player comes indeed from the correct IP address bool locked = false; if ((*qresult)[2].GetUInt8() == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*qresult)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if ( strcmp((*qresult)[3].GetString(),get_remote_address().c_str()) ) { DEBUG_LOG("[AuthChallenge] Account IP differs"); result = WOW_FAIL_SUSPENDED; locked = true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!locked) { uint32 accId = (*qresult)[1].GetUInt32(); ///- If the account is banned, reject the logon attempt QueryResult* banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE " "id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)", accId); if (banresult) { if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { result = WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned account %s (Id: %u) tries to login!", _login.c_str(), accId); } else { result = WOW_FAIL_SUSPENDED; BASIC_LOG("[AuthChallenge] Temporarily banned account %s (Id: %u) tries to login!",_login.c_str(), accId); } delete banresult; } else { ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = (*qresult)[0].GetCppString(); ///- Don't calculate (v, s) if there are already some in the database std::string databaseV = (*qresult)[5].GetCppString(); std::string databaseS = (*qresult)[6].GetCppString(); DEBUG_LOG("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2, bytes are stored as hexstring if (databaseV.size() != s_BYTE_SIZE*2 || databaseS.size() != s_BYTE_SIZE*2) _SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } result = WOW_SUCCESS; uint8 secLevel = (*qresult)[4].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; BASIC_LOG("[AuthChallenge] account %s (Id: %u) is using '%c%c%c%c' locale (%u)", _login.c_str (), accId, ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); } } delete qresult; } else if (sConfig.GetBoolDefault("AutoRegistration", false)) { if (_safelogin.find_first_of("\t\v\b\f\a\n\r\\\"\'\? <>[](){}_=+-|/!@#$%^&*~`.,\0") == _safelogin.npos && _safelogin.length() > 3) { QueryResult* checkIPresult = LoginDatabase.PQuery("SELECT COUNT(last_ip) FROM account WHERE last_ip = '%s'",get_remote_address().c_str()); int32 regCount = checkIPresult ? (*checkIPresult)[0].GetUInt32() : 0; if (regCount >= sConfig.GetIntDefault("AutoRegistration.Amount", 1)) { BASIC_LOG("[AuthChallenge] Impossible auto-register account %s, number of auto-registered accouts is %u, but allowed only %u", _safelogin.c_str(),regCount, sConfig.GetIntDefault("AutoRegistration.Amount", 1)); // result = WOW_FAIL_DB_BUSY; result = WOW_FAIL_DISCONNECTED; } else { std::transform(_safelogin.begin(), _safelogin.end(), _safelogin.begin(), std::towupper); Sha1Hash sha; sha.Initialize(); sha.UpdateData(_safelogin); sha.UpdateData(":"); sha.UpdateData(_safelogin); sha.Finalize(); std::string encoded; hexEncodeByteArray(sha.GetDigest(), sha.GetLength(), encoded); LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", _safelogin.c_str(), encoded.c_str()); _SetVSFields(encoded); BASIC_LOG("[AuthChallenge] account %s auto-registered (count %u)!",_safelogin.c_str(), ++regCount); result = WOW_SUCCESS; _accountSecurityLevel = SEC_PLAYER; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; } if (checkIPresult) delete checkIPresult; } } else result = WOW_FAIL_UNKNOWN_ACCOUNT; } pkt << uint8(CMD_AUTH_LOGON_CHALLENGE); pkt << uint8(0x00); pkt << uint8(result); switch (result) { case WOW_SUCCESS: { b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; MANGOS_ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if (securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if (securityFlags & 0x04) // Security token input { pkt << uint8(1); } break; } case WOW_FAIL_UNKNOWN0: case WOW_FAIL_UNKNOWN1: case WOW_FAIL_SUSPENDED: case WOW_FAIL_BANNED: case WOW_FAIL_UNKNOWN_ACCOUNT: case WOW_FAIL_INCORRECT_PASSWORD: case WOW_FAIL_ALREADY_ONLINE: case WOW_FAIL_NO_TIME: case WOW_FAIL_DB_BUSY: case WOW_FAIL_VERSION_INVALID: case WOW_FAIL_VERSION_UPDATE: case WOW_FAIL_INVALID_SERVER: case WOW_FAIL_FAIL_NOACCESS: case WOW_SUCCESS_SURVEY: case WOW_FAIL_PARENTCONTROL: case WOW_FAIL_LOCKED_ENFORCED: case WOW_FAIL_TRIAL_ENDED: case WOW_FAIL_USE_BATTLENET: case WOW_FAIL_TOO_FAST: case WOW_FAIL_CHARGEBACK: case WOW_FAIL_GAME_ACCOUNT_LOCKED: case WOW_FAIL_INTERNET_GAME_ROOM_WITHOUT_BNET: case WOW_FAIL_UNLOCKABLE_LOCK: case WOW_FAIL_DISCONNECTED: break; default: BASIC_LOG("[AuthChallenge] unknown CMD_AUTH_LOGON_CHALLENGE execution result %u!", result); break; } send((char const*)pkt.contents(), pkt.size()); return true; }
/// Accept the connection and set the s random value for SRP6 void AuthSocket::OnAccept() { BASIC_LOG("Accepting connection from '%s'", get_remote_address().c_str()); }
void WorldSession::HandleForceSpeedChangeAckOpcodes(WorldPacket &recv_data) { uint32 opcode = recv_data.GetOpcode(); DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); /* extract packet */ ObjectGuid guid; MovementInfo movementInfo; float newspeed; recv_data >> guid.ReadAsPacked(); recv_data >> Unused<uint32>(); // counter or moveEvent recv_data >> movementInfo; recv_data >> newspeed; // now can skip not our packet if(_player->GetObjectGuid() != guid) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /*----------------*/ // client ACK send one packet for mounted/run case and need skip all except last from its // in other cases anti-cheat check can be fail in false case UnitMoveType move_type; UnitMoveType force_move_type; static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; switch(opcode) { case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; default: sLog.outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); return; } // skip all forced speed changes except last and unexpected // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. if(_player->m_forced_speed_changes[force_move_type] > 0) { --_player->m_forced_speed_changes[force_move_type]; if(_player->m_forced_speed_changes[force_move_type] > 0) return; } if (!_player->GetTransport() && fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) { if(_player->GetSpeed(move_type) > newspeed) // must be greater - just correct { sLog.outError("%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", move_type_name[move_type], _player->GetName(), _player->GetSpeed(move_type), newspeed); _player->SetSpeedRate(move_type,_player->GetSpeedRate(move_type),true); } else // must be lesser - cheating { BASIC_LOG("Player %s from account id %u kicked for incorrect speed (must be %f instead %f)", _player->GetName(),_player->GetSession()->GetAccountId(),_player->GetSpeed(move_type), newspeed); _player->GetSession()->KickPlayer(); } } }
void WorldSession::HandleCharDeleteOpcode(WorldPacket& recv_data) { ObjectGuid guid; recv_data >> guid; // can't delete loaded character if (sObjectMgr.GetPlayer(guid)) return; uint32 accountId = 0; std::string name; // is guild leader if (sGuildMgr.GetGuildByLeader(guid)) { WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER; SendPacket(&data); return; } // is arena team captain if (sObjectMgr.GetArenaTeamByCaptain(guid)) { WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN; SendPacket(&data); return; } uint32 lowguid = guid.GetCounter(); QueryResult* result = CharacterDatabase.PQuery("SELECT account,name FROM characters WHERE guid='%u'", lowguid); if (result) { Field* fields = result->Fetch(); accountId = fields[0].GetUInt32(); name = fields[1].GetCppString(); delete result; } // prevent deleting other players' characters using cheating tools if (accountId != GetAccountId()) return; std::string IP_str = GetRemoteAddress(); BASIC_LOG("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), lowguid); sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), lowguid); if (sLog.IsOutCharDump()) // optimize GetPlayerDump call { std::string dump = PlayerDumpWriter().GetDump(lowguid); sLog.outCharDump(dump.c_str(), GetAccountId(), lowguid, name.c_str()); } Player::DeleteFromDB(guid, GetAccountId()); WorldPacket data(SMSG_CHAR_DELETE, 1); data << (uint8)CHAR_DELETE_SUCCESS; SendPacket(&data); }
void WorldSession::HandleCharCreateOpcode(WorldPacket& recv_data) { std::string name; uint8 race_, class_; recv_data >> name; recv_data >> race_; recv_data >> class_; // extract other data required for player creating uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; recv_data >> gender >> skin >> face; recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases if (GetSecurity() == SEC_PLAYER) { if (uint32 mask = sWorld.getConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED)) { bool disabled = false; Team team = Player::TeamForRace(race_); switch (team) { case ALLIANCE: disabled = mask & (1 << 0); break; case HORDE: disabled = mask & (1 << 1); break; default: break; } if (disabled) { data << (uint8)CHAR_CREATE_DISABLED; SendPacket(&data); return; } } } ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); if (!classEntry || !raceEntry) { data << (uint8)CHAR_CREATE_FAILED; SendPacket(&data); sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_); return; } // prevent character creating Expansion race without Expansion account if (raceEntry->expansion > Expansion()) { data << (uint8)CHAR_CREATE_EXPANSION; sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)", Expansion(), GetAccountId(), raceEntry->expansion, race_); SendPacket(&data); return; } // prevent character creating with invalid name if (!normalizePlayerName(name)) { data << (uint8)CHAR_NAME_NO_NAME; SendPacket(&data); sLog.outError("Account:[%d] but tried to Create character with empty [name]", GetAccountId()); return; } // check name limitations uint8 res = ObjectMgr::CheckPlayerName(name, true); if (res != CHAR_NAME_SUCCESS) { data << uint8(res); SendPacket(&data); return; } if (GetSecurity() == SEC_PLAYER && sObjectMgr.IsReservedName(name)) { data << (uint8)CHAR_NAME_RESERVED; SendPacket(&data); return; } if (sObjectMgr.GetPlayerGuidByName(name)) { data << (uint8)CHAR_CREATE_NAME_IN_USE; SendPacket(&data); return; } QueryResult* resultacct = LoginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%u'", GetAccountId()); if (resultacct) { Field* fields = resultacct->Fetch(); uint32 acctcharcount = fields[0].GetUInt32(); delete resultacct; if (acctcharcount >= sWorld.getConfig(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT)) { data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT; SendPacket(&data); return; } } QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%u'", GetAccountId()); uint8 charcount = 0; if (result) { Field* fields = result->Fetch(); charcount = fields[0].GetUInt8(); delete result; if (charcount >= sWorld.getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM)) { data << (uint8)CHAR_CREATE_SERVER_LIMIT; SendPacket(&data); return; } } bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER; CinematicsSkipMode skipCinematics = CinematicsSkipMode(sWorld.getConfig(CONFIG_UINT32_SKIP_CINEMATICS)); bool have_same_race = false; if (!AllowTwoSideAccounts || skipCinematics == CINEMATICS_SKIP_SAME_RACE) { QueryResult* result2 = CharacterDatabase.PQuery("SELECT race FROM characters WHERE account = '%u' %s", GetAccountId(), (skipCinematics == CINEMATICS_SKIP_SAME_RACE) ? "" : "LIMIT 1"); if (result2) { Team team_ = Player::TeamForRace(race_); Field* field = result2->Fetch(); uint8 acc_race = field[0].GetUInt32(); // need to check team only for first character // TODO: what to if account already has characters of both races? if (!AllowTwoSideAccounts) { if (acc_race == 0 || Player::TeamForRace(acc_race) != team_) { data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION; SendPacket(&data); delete result2; return; } } // search same race for cinematic or same class if need // TODO: check if cinematic already shown? (already logged in?; cinematic field) while (skipCinematics == CINEMATICS_SKIP_SAME_RACE && !have_same_race) { if (!result2->NextRow()) break; field = result2->Fetch(); acc_race = field[0].GetUInt32(); have_same_race = race_ == acc_race; } delete result2; } } Player* pNewChar = new Player(this); if (!pNewChar->Create(sObjectMgr.GeneratePlayerLowGuid(), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId)) { // Player not create (race/class problem?) delete pNewChar; data << (uint8)CHAR_CREATE_ERROR; SendPacket(&data); return; } if ((have_same_race && skipCinematics == CINEMATICS_SKIP_SAME_RACE) || skipCinematics == CINEMATICS_SKIP_ALL) pNewChar->setCinematic(1); // not show intro pNewChar->SetAtLoginFlag(AT_LOGIN_FIRST); // First login // Player created, save it now pNewChar->SaveToDB(); charcount += 1; LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%u' AND realmid = '%u'", GetAccountId(), realmID); LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID); data << (uint8)CHAR_CREATE_SUCCESS; SendPacket(&data); std::string IP_str = GetRemoteAddress(); BASIC_LOG("Account: %d (IP: %s) Create Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow()); sLog.outChar("Account: %d (IP: %s) Create Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow()); delete pNewChar; // created only to call SaveToDB() }
int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { // NOTE: ATM the socket is singlethread, have this in mind ... uint8 digest[20]; uint32 clientSeed, id, security; uint32 unk2; uint32 BuiltNumberClient; uint8 expansion = 0; LocaleConstant locale; std::string account; Sha1Hash sha1; BigNumber v, s, g, N, K; WorldPacket packet, SendAddonPacked; // 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* 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(); expansion = ((sWorld.getConfig(CONFIG_UINT32_EXPANSION) > fields[7].GetUInt8()) ? fields[7].GetUInt8() : sWorld.getConfig(CONFIG_UINT32_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); delete result; BASIC_LOG("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); return -1; } } id = fields[0].GetUInt32(); security = fields[1].GetUInt16(); if (security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB security = SEC_ADMINISTRATOR; K.SetHexStr(fields[2].GetString()); time_t mutetime = time_t (fields[8].GetUInt64()); uint8 tempLoc = LocaleConstant(fields[9].GetUInt8()); if (tempLoc >= static_cast<uint8>(MAX_LOCALE)) locale = LOCALE_enUS; else locale = LocaleConstant(tempLoc); delete result; // Re-check account ban (same check as in realmd) QueryResult* banresult = LoginDatabase.PQuery("SELECT 1 FROM account_banned WHERE id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)" "UNION " "SELECT 1 FROM ip_banned WHERE (unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", id, GetRemoteAddress().c_str()); 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 && AccountTypes(security) < allowedAccountType) { WorldPacket Packet(SMSG_AUTH_RESPONSE, 1); Packet << uint8(AUTH_UNAVAILABLE); SendPacket(packet); BASIC_LOG("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, nullptr); 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. static SqlStatementID updAccount; SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE account SET last_ip = ? WHERE username = ?"); stmt.PExecute(address.c_str(), account.c_str()); // NOTE ATM the socket is single-threaded, have this in mind ... ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale), -1); m_Crypt.Init(&K); m_Session->LoadTutorialsData(); // 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 serverId; uint32 BuiltNumberClient; uint32 id, security; LocaleConstant locale; std::string account, os; BigNumber v, s, g, N, K; WorldPacket packet, SendAddonPacked; // Read the content of the packet recvPacket >> BuiltNumberClient; recvPacket >> serverId; recvPacket >> account; recvPacket >> clientSeed; recvPacket.read(digest, 20); DEBUG_LOG("WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, clientseed %u", BuiltNumberClient, serverId, 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 *result = LoginDatabase.PQuery("SELECT a.id, aa.gmLevel, a.sessionkey, a.last_ip, a.locked, a.v, a.s, a.mutetime, a.locale, a.os, a.flags, " "ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate FROM account a LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, %u) " "LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 WHERE a.username = '******' ORDER BY aa.RealmID DESC LIMIT 1", realmID, 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(); 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); delete result; BASIC_LOG("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); return -1; } } id = fields[0].GetUInt32(); security = sAccountMgr.GetSecurity(id); //fields[1].GetUInt16 (); if (security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB security = SEC_ADMINISTRATOR; K.SetHexStr(fields[2].GetString()); time_t mutetime = time_t (fields[7].GetUInt64()); locale = LocaleConstant(fields[8].GetUInt8()); if (locale >= MAX_LOCALE) locale = LOCALE_enUS; os = fields[9].GetString(); uint32 accFlags = fields[10].GetUInt32(); delete result; bool isBanned = fields[11].GetBool(); if (isBanned || sAccountMgr.IsIPBanned(GetRemoteAddress())) { 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 AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType) { WorldPacket Packet(SMSG_AUTH_RESPONSE, 1); Packet << uint8(AUTH_UNAVAILABLE); SendPacket(packet); BASIC_LOG("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. static SqlStatementID updAccount; SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE account SET last_ip = ? WHERE username = ?"); stmt.PExecute(address.c_str(), account.c_str()); // NOTE ATM the socket is single-threaded, have this in mind ... ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), mutetime, locale), -1); m_Crypt.SetKey(K.AsByteArray()); m_Crypt.Init(); m_Session->SetUsername(account); m_Session->SetGameBuild(BuiltNumberClient); m_Session->SetAccountFlags(accFlags); ClientOSType clientOs; if (os == "niW") clientOs = CLIENT_OS_WIN; else if (os == "XSO") clientOs = CLIENT_OS_MAC; else { sLog.outError("WorldSocket::HandleAuthSession: Unrecognized OS '%s' for account '%s' from %s", os.c_str(), account.c_str(), address.c_str()); return -1; } m_Session->SetOS(clientOs); m_Session->LoadTutorialsData(); m_Session->InitWarden(&K); // 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; }