void InstanceSaveManager::_DelHelper(DatabaseType &db, const char *fields, const char *table, const char *queryTail,...) { Tokens fieldTokens = StrSplit(fields, ", "); ASSERT(fieldTokens.size() != 0); va_list ap; char szQueryTail [MAX_QUERY_LEN]; va_start(ap, queryTail); vsnprintf(szQueryTail, MAX_QUERY_LEN, queryTail, ap); va_end(ap); QueryResult_AutoPtr result = db.PQuery("SELECT %s FROM %s %s", fields, table, szQueryTail); if (result) { do { Field *fields = result->Fetch(); std::ostringstream ss; for (size_t i = 0; i < fieldTokens.size(); i++) { std::string fieldValue = fields[i].GetCppString(); db.escape_string(fieldValue); ss << (i != 0 ? " AND " : "") << fieldTokens[i] << " = '" << fieldValue << "'"; } db.DirectPExecute("DELETE FROM %s WHERE %s", table, ss.str().c_str()); } while (result->NextRow()); } }
/// 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(); AccountsDatabase.DirectPExecute("UPDATE account_session SET v = '%s', s = '%s' WHERE username = '******'", v_hex, s_hex, _safelogin.c_str() ); OPENSSL_free((void*)v_hex); OPENSSL_free((void*)s_hex); }
/// 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)) { sLog.outBasic("User '%s' successfully authenticated", _login.c_str()); uint8 OS; if (!strcmp(operatingSystem_.c_str(), "Win")) OS = CLIENT_OS_WIN; else if (!strcmp(operatingSystem_.c_str(), "OSX")) OS = CLIENT_OS_OSX; else if (!strcmp(operatingSystem_.c_str(), "CHA") || !strcmp(operatingSystem_.c_str(), "CHAT")) OS = CLIENT_OS_CHAT; else { OS = CLIENT_OS_UNKNOWN; AccountsDatabase.escape_string(operatingSystem_); sLog.outLog(LOG_WARDEN, "Client %s got unsupported operating system (%s)", _safelogin.c_str(), operatingSystem_.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(); QueryResultAutoPtr result = AccountsDatabase.PQuery("SELECT account_id FROM account WHERE username = '******'", _safelogin.c_str()); if (!result) { 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)); } return true; } uint32 accId = result->Fetch()->GetUInt32(); // direct to be sure that values will be set before character choose, this will slow down logging in a bit ;p AccountsDatabase.DirectPExecute("UPDATE account_session SET session_key = '%s' WHERE account_id = '%u'", K_hex, accId); static SqlStatementID updateAccount; SqlStatement stmt = AccountsDatabase.CreateStatement(updateAccount, "UPDATE account SET last_ip = ?, last_local_ip = ?, last_login = NOW(), locale_id = ?, failed_logins = 0, client_os_version_id = ? WHERE account_id = ?"); std::string tmpIp = get_remote_address(); stmt.addString(tmpIp.c_str()); stmt.addString(localIp_.c_str()); stmt.addUInt8(uint8(GetLocaleByName(_localizationName))); stmt.addUInt8(OS); stmt.addUInt32(accId); stmt.DirectExecute(); 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)); } sLog.outBasic("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); if (MaxWrongPassCount > 0) { static SqlStatementID updateAccountFailedLogins; //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP SqlStatement stmt = AccountsDatabase.CreateStatement(updateAccountFailedLogins, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?"); stmt.addString(_login); stmt.Execute(); if (QueryResultAutoPtr loginfail = AccountsDatabase.PQuery("SELECT account_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(); AccountsDatabase.PExecute("INSERT INTO account_punishment VALUES ('%u', '%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, 'Realm', 'Incorrect password for: %u times. Ban for: %u seconds')", acc_id, PUNISHMENT_BAN, WrongPassBanTime, failed_logins, WrongPassBanTime); sLog.outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); } else { std::string current_ip = get_remote_address(); AccountsDatabase.escape_string(current_ip); AccountsDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Realm','Incorrect password for: %u times. Ban for: %u seconds')", current_ip.c_str(), WrongPassBanTime, failed_logins, WrongPassBanTime); sLog.outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); } } } } } return true; }