Merge pull request #321 from NicknineTheEagle/nn/auth

Auth manager changes
This commit is contained in:
Detanup01
2025-08-12 19:26:59 +02:00
committed by GitHub
7 changed files with 233 additions and 96 deletions

View File

@@ -1,10 +1,9 @@
#include "dll/auth.h"
#define STEAM_ID_OFFSET_TICKET (4 + 8)
#define STEAM_TICKET_PROCESS_TIME 0.03
static inline int generate_random_int() {
static inline int generate_random_int()
{
int a;
randombytes((char *)&a, sizeof(a));
return a;
@@ -107,7 +106,7 @@ static std::vector<uint8_t> sign_auth_data(const std::string &private_key_conten
mbedtls_entropy_free(&entropy_ctx);
#ifndef EMU_RELEASE_BUILD
// we nedd a live object until the printf does its job, hence this special handling
// we need a live object until the printf does its job, hence this special handling
std::string err_msg(256, 0);
mbedtls_strerror(result, &err_msg[0], err_msg.size());
PRINT_DEBUG("failed to parse private key: %s", err_msg.c_str());
@@ -161,7 +160,7 @@ static std::vector<uint8_t> sign_auth_data(const std::string &private_key_conten
signature.clear();
#ifndef EMU_RELEASE_BUILD
// we nedd a live object until the printf does its job, hence this special handling
// we need a live object until the printf does its job, hence this special handling
std::string err_msg(256, 0);
mbedtls_strerror(result, &err_msg[0], err_msg.size());
PRINT_DEBUG("RSA signing failed: %s", err_msg.c_str());
@@ -219,25 +218,18 @@ std::vector<uint8_t> AppTicketGC::Serialize() const
{
const uint64_t steam_id = id.ConvertToUint64();
// must be 52
// must be 24
constexpr size_t total_size =
sizeof(STEAM_APPTICKET_GCLen) +
sizeof(GCToken) +
sizeof(steam_id) +
sizeof(ticketGenDate) +
sizeof(STEAM_APPTICKET_SESSIONLEN) +
sizeof(one) +
sizeof(two) +
sizeof(ExternalIP) +
sizeof(InternalIP) +
sizeof(TimeSinceStartup) +
sizeof(TicketGeneratedCount);
sizeof(ticketGenDate);
// check the size at compile time, we must ensure the correct size
#ifndef EMU_RELEASE_BUILD
static_assert(
total_size == 52,
"AUTH::AppTicketGC::SER calculated size of serialized data != 52 bytes, your compiler has some incorrect sizes"
total_size == 24,
"AUTH::AppTicketGC::SER calculated size of serialized data != 24 bytes, your compiler has some incorrect sizes"
);
#endif
@@ -246,15 +238,11 @@ std::vector<uint8_t> AppTicketGC::Serialize() const
" GCToken: " "%" PRIu64 "\n"
" user steam_id: " "%" PRIu64 "\n"
" ticketGenDate: %u\n"
" ExternalIP: 0x%08X, InternalIP: 0x%08X\n"
" TimeSinceStartup: %u, TicketGeneratedCount: %u\n"
" SER size = %zu",
GCToken,
steam_id,
ticketGenDate,
ExternalIP, InternalIP,
TimeSinceStartup, TicketGeneratedCount,
total_size
);
@@ -271,6 +259,58 @@ pBuffer += sizeof(v)
SER_VAR(GCToken);
SER_VAR(steam_id);
SER_VAR(ticketGenDate);
#undef SER_VAR
#ifndef EMU_RELEASE_BUILD
// we nedd a live object until the printf does its job, hence this special handling
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
PRINT_DEBUG("final data [%zu bytes]:\n %s", buffer.size(), str.c_str());
#endif
return buffer;
}
std::vector<uint8_t> AppTicketSession::Serialize() const
{
// must be 28
constexpr size_t total_size =
sizeof(STEAM_APPTICKET_SESSIONLEN) +
sizeof(one) +
sizeof(two) +
sizeof(ExternalIP) +
sizeof(InternalIP) +
sizeof(TimeSinceStartup) +
sizeof(TicketGeneratedCount);
// check the size at compile time, we must ensure the correct size
#ifndef EMU_RELEASE_BUILD
static_assert(
total_size == 28,
"AUTH::AppTicketSession::SER calculated size of serialized data != 28 bytes, your compiler has some incorrect sizes"
);
#endif
PRINT_DEBUG(
"\n"
" ExternalIP: 0x%08X, InternalIP: 0x%08X\n"
" TimeSinceStartup: %u, TicketGeneratedCount: %u\n"
" SER size = %zu",
ExternalIP, InternalIP,
TimeSinceStartup, TicketGeneratedCount,
total_size
);
std::vector<uint8_t> buffer{};
buffer.resize(total_size);
uint8_t *pBuffer = &buffer[0];
#define SER_VAR(v) \
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
pBuffer += sizeof(v)
SER_VAR(STEAM_APPTICKET_SESSIONLEN);
SER_VAR(one);
SER_VAR(two);
@@ -444,7 +484,9 @@ std::vector<uint8_t> Auth_Data::Serialize() const
/*
* layout of Auth_Data with GC:
* ------------------------
* X bytes: GC data blob (currently 52 bytes)
* X bytes: GC data blob (currently 24 bytes)
* ------------------------
* X bytes: session data blob (currently 28 bytes)
* ------------------------
* 4 bytes: remaining Auth_Data blob size (4 + Y + Z)
* ------------------------
@@ -502,12 +544,15 @@ std::vector<uint8_t> Auth_Data::Serialize() const
size_t total_size_without_siglen = ticket_data_layout_length;
std::vector<uint8_t> GCData{};
std::vector<uint8_t> SessionData{};
size_t gc_data_layout_length = 0;
if (HasGC) {
/*
* layout of GC data:
* ------------------------
* X bytes: GC data blob (currently 52 bytes)
* X bytes: GC data blob (currently 24 bytes)
* ------------------------
* X bytes: session data blob (currently 28 bytes)
* ------------------------
* 4 bytes: remaining Auth_Data blob size
* ------------------------
@@ -515,9 +560,12 @@ std::vector<uint8_t> Auth_Data::Serialize() const
* total layout length = X + 4
*/
GCData = GC.Serialize();
gc_data_layout_length +=
GCData.size() +
sizeof(uint32_t);
gc_data_layout_length += GCData.size();
if (HasSession) {
SessionData = Session.Serialize();
gc_data_layout_length += SessionData.size();
}
gc_data_layout_length += sizeof(uint32_t);
total_size_without_siglen += gc_data_layout_length;
}
@@ -542,6 +590,12 @@ pBuffer += sizeof(v)
memcpy(pBuffer, GCData.data(), GCData.size());
pBuffer += GCData.size();
// Handle session data if applicable
if (HasSession) {
memcpy(pBuffer, SessionData.data(), SessionData.size());
pBuffer += SessionData.size();
}
// when GC data is written (HasGC),
// the next 4 bytes after the GCData will be the length of the remaining data in the final buffer
// i.e. final buffer size - length of GCData layout
@@ -630,25 +684,25 @@ void Auth_Manager::launch_callback_gs_steam2(CSteamID steam_id, uint32_t user_id
GSClientSteam2Accept_t data2{};
data2.m_UserID = user_id;
data2.m_SteamID = steam_id.ConvertToUint64();
callbacks->addCBResult(data2.k_iCallback, &data2, sizeof(data2));
callbacks->addCBResult(data2.k_iCallback, &data2, sizeof(data2), STEAM_TICKET_PROCESS_TIME);
// Fire Steam3 callback.
GSClientApprove_t data3{};
data3.m_SteamID = data3.m_OwnerSteamID = steam_id;
callbacks->addCBResult(data3.k_iCallback, &data3, sizeof(data3));
callbacks->addCBResult(data3.k_iCallback, &data3, sizeof(data3), STEAM_TICKET_PROCESS_TIME * 2.0);
} else {
// Fire Steam2 callback. This will kick the client so no need to send Steam3 callback.
/*
GSClientSteam2Deny_t data2{};
data2.m_UserID = user_id;
data2.m_eSteamError = k_EDenyNotLoggedOn;
callbacks->addCBResult(data2.k_iCallback, &data2, sizeof(data2));
callbacks->addCBResult(data2.k_iCallback, &data2, sizeof(data2), STEAM_TICKET_PROCESS_TIME);
*/
/*
// Fire Steam3 callback. Only one of these is actually needed to kick the client.
GSClientDeny_t data3{};
data3.m_SteamID = steam_id;
data3.m_eDenyReason = k_EDenyNotLoggedOn; //TODO: other reasons?
callbacks->addCBResult(data3.k_iCallback, &data3, sizeof(data3));
*/
callbacks->addCBResult(data3.k_iCallback, &data3, sizeof(data3), STEAM_TICKET_PROCESS_TIME);
}
}
@@ -657,16 +711,16 @@ void Auth_Manager::launch_callback_gs(CSteamID id, bool approved)
if (approved) {
GSClientApprove_t data{};
data.m_SteamID = data.m_OwnerSteamID = id;
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), STEAM_TICKET_PROCESS_TIME);
} else {
GSClientDeny_t data{};
data.m_SteamID = id;
data.m_eDenyReason = k_EDenyNotLoggedOn; //TODO: other reasons?
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), STEAM_TICKET_PROCESS_TIME);
}
}
Auth_Data Auth_Manager::getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
Auth_Data Auth_Manager::getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, bool add_session_header )
{
#define IP4_AS_DWORD_LITTLE_ENDIAN(a,b,c,d) (((uint32_t)d)<<24 | ((uint32_t)c)<<16 | ((uint32_t)b)<<8 | (uint32_t)a)
@@ -707,36 +761,50 @@ Auth_Data Auth_Manager::getTicketData( void *pTicket, int cbMaxTicket, uint32 *p
if (settings->use_gc_token)
{
ticket_data.HasGC = true;
ticket_data.GC.GCToken = generate_random_int();
ticket_data.HasSession = add_session_header;
ticket_data.GC.GCToken = ((uint64_t)ticket_data.number << 32) | (uint64_t)generate_random_int();
ticket_data.GC.id = steam_id;
ticket_data.GC.ticketGenDate = (uint32_t)GenDate.count();
ticket_data.GC.ExternalIP = IP4_AS_DWORD_LITTLE_ENDIAN(127, 0, 0, 1);
ticket_data.GC.InternalIP = IP4_AS_DWORD_LITTLE_ENDIAN(127, 0, 0, 1);
ticket_data.GC.TimeSinceStartup = (uint32_t)std::chrono::duration_cast<std::chrono::seconds>(curTime - startup_time).count();
ticket_data.GC.TicketGeneratedCount = get_ticket_count();
ticket_data.Session.ExternalIP = IP4_AS_DWORD_LITTLE_ENDIAN(127, 0, 0, 1);
ticket_data.Session.InternalIP = IP4_AS_DWORD_LITTLE_ENDIAN(127, 0, 0, 1);
ticket_data.Session.TimeSinceStartup = (uint32_t)std::chrono::duration_cast<std::chrono::seconds>(curTime - startup_time).count();
ticket_data.Session.TicketGeneratedCount = get_ticket_count();
}
std::vector<uint8_t> ser = ticket_data.Serialize();
uint32_t ser_size = static_cast<uint32_t>(ser.size());
*pcbTicket = ser_size;
if (cbMaxTicket > 0 && static_cast<uint32_t>(cbMaxTicket) >= ser_size) {
if (static_cast<uint32_t>(cbMaxTicket) >= ser_size) {
memcpy(pTicket, ser.data(), ser_size);
*pcbTicket = ser_size;
} else {
*pcbTicket = 0;
}
}
else
{
memset(pTicket, 123, cbMaxTicket);
((char *)pTicket)[0] = 0x14;
((char *)pTicket)[1] = 0;
((char *)pTicket)[2] = 0;
((char *)pTicket)[3] = 0;
uint64 steam_id_buff = steam_id.ConvertToUint64();
memcpy((char *)pTicket + STEAM_ID_OFFSET_TICKET, &steam_id_buff, sizeof(steam_id_buff));
*pcbTicket = STEAM_TICKET_MIN_SIZE;
uint32 ttt = generate_steam_ticket_id();
ticket_data.id = steam_id;
ticket_data.number = ttt;
ticket_data.number = generate_steam_ticket_id();
memcpy(((char *)pTicket) + sizeof(uint64), &ttt, sizeof(ttt));
memset(pTicket, 0, cbMaxTicket);
uint32_t gc_len = STEAM_APPTICKET_GCLen;
uint64_t token = ((uint64_t)ticket_data.number << 32) | (uint64_t)generate_random_int();
uint64_t steam_id_buff = steam_id.ConvertToUint64();
uint32_t ticket_gen_date = (uint32_t)std::chrono::system_clock::now().time_since_epoch().count();
uint8_t *pBuffer = (uint8_t *)pTicket;
#define SER_VAR(v) \
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
pBuffer += sizeof(v)
SER_VAR(gc_len);
SER_VAR(token);
SER_VAR(steam_id_buff);
SER_VAR(ticket_gen_date);
#undef SER_VAR
*pcbTicket = STEAM_TICKET_MIN_SIZE;
}
#undef IP4_AS_DWORD_LITTLE_ENDIAN
@@ -756,9 +824,9 @@ HAuthTicket Auth_Manager::getTicket( void *pTicket, int cbMaxTicket, uint32 *pcb
if (cbMaxTicket > STEAM_AUTH_TICKET_SIZE) cbMaxTicket = STEAM_AUTH_TICKET_SIZE;
}
Auth_Data ticket_data = getTicketData(pTicket, cbMaxTicket, pcbTicket );
Auth_Data ticket_data = getTicketData(pTicket, cbMaxTicket, pcbTicket, true);
if (*pcbTicket > static_cast<uint32>(cbMaxTicket)) {
if (*pcbTicket == 0) {
return k_HAuthTicketInvalid;
}
@@ -823,68 +891,115 @@ bool Auth_Manager::SendSteam2UserConnect( uint32 unUserID, const void *pvRawKey,
// pvCookie is Steam3 auth ticket, it comes from us.
// Steam3 ticket is technically optional but it should always be there if the client is using Goldberg
// so there's no real need to check Steam2 ticket.
if (cubCookie < STEAM_TICKET_MIN_SIZE) return false;
Auth_Data data;
uint64 id;
memcpy(&id, (char *)pvCookie + STEAM_ID_OFFSET_TICKET, sizeof(id));
uint32 number;
memcpy(&number, ((char *)pvCookie) + sizeof(uint64), sizeof(number));
data.id = CSteamID(id);
data.number = number;
if (pSteamIDUser) *pSteamIDUser = data.id;
// HACK: Generate Steam ID from IP address for unknown clients.
CSteamID fallbackID(unIPPublic, k_EUniversePublic, k_EAccountTypeIndividual);
Auth_Data data = validateTicket(pvCookie, cubCookie, fallbackID, pSteamIDUser);
if (!data.id.IsValid())
return false;
for (auto & t : inbound) {
if (t.id == data.id) {
//Should this return false?
launch_callback_gs_steam2(id, unUserID, true);
launch_callback_gs_steam2(data.id, unUserID, true);
return true;
}
}
inbound.push_back(data);
launch_callback_gs_steam2(id, unUserID, true);
launch_callback_gs_steam2(data.id, unUserID, true);
return true;
}
bool Auth_Manager::SendUserConnectAndAuthenticate( uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser )
{
if (cubAuthBlobSize < STEAM_TICKET_MIN_SIZE) return false;
Auth_Data data;
uint64 id;
memcpy(&id, (char *)pvAuthBlob + STEAM_ID_OFFSET_TICKET, sizeof(id));
uint32 number;
memcpy(&number, ((char *)pvAuthBlob) + sizeof(uint64), sizeof(number));
data.id = CSteamID(id);
data.number = number;
if (pSteamIDUser) *pSteamIDUser = data.id;
// HACK: Generate Steam ID from IP address for unknown clients.
CSteamID fallbackID(unIPClient, k_EUniversePublic, k_EAccountTypeIndividual);
Auth_Data data = validateTicket(pvAuthBlob, cubAuthBlobSize, fallbackID, pSteamIDUser);
if (!data.id.IsValid())
return false;
for (auto & t : inbound) {
if (t.id == data.id) {
//Should this return false?
launch_callback_gs(id, true);
launch_callback_gs(data.id, true);
return true;
}
}
inbound.push_back(data);
launch_callback_gs(id, true);
launch_callback_gs(data.id, true);
return true;
}
EBeginAuthSessionResult Auth_Manager::beginAuth(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID )
Auth_Data Auth_Manager::validateTicket(const void *pAuthTicket, uint32 cbAuthTicket, CSteamID fallbackID, CSteamID *pSteamIDUser)
{
if (cbAuthTicket < STEAM_TICKET_MIN_SIZE) return k_EBeginAuthSessionResultInvalidTicket;
if (cbAuthTicket < STEAM_TICKET_MIN_SIZE)
return {};
Auth_Data data;
uint64 id;
memcpy(&id, (char *)pAuthTicket + STEAM_ID_OFFSET_TICKET, sizeof(id));
uint32 number;
memcpy(&number, ((char *)pAuthTicket) + sizeof(uint64), sizeof(number));
data.id = CSteamID(id);
data.number = number;
if (*(uint32 *)pAuthTicket == 0x554d4548) { // "HEMU"
// This is a SmartSteamEmu ticket.
// 0x00: header magic
// 0x04: ticket version
// 0x08: external IP
// 0x0c: zero
// 0x10: Steam ID
// rest is unknown
PRINT_DEBUG("SmartSteamEmu ticket detected");
uint32 version;
memcpy(&version, (char *)pAuthTicket + 0x04, sizeof(version));
if (version != 315)
return {};
uint64 id;
memcpy(&id, (char *)pAuthTicket + 0x10, sizeof(id));
data.id = CSteamID(id);
data.number = 0;
} else if (*(uint32 *)((char *)pAuthTicket + 0x08) == 0x726576) {
// This is a RevEmu ticket.
PRINT_DEBUG("RevEmu ticket detected");
uint32 version;
memcpy(&version, (char *)pAuthTicket + 0x00, sizeof(version));
if (version < 83 || cbAuthTicket < 0xa8)
return {};
uint64 id;
memcpy(&id, (char *)pAuthTicket + 0x10, sizeof(id));
data.id = CSteamID(id);
data.number = 0;
} else if (*(uint32 *)pAuthTicket == STEAM_APPTICKET_GCLen) {
// Assume this is a standard Steam ticket. Used by us and real Steam.
// TODO: More robust checks.
PRINT_DEBUG("standard ticket detected");
uint32 number;
memcpy(&number, ((char *)pAuthTicket) + 0x08, sizeof(number));
uint64 id;
memcpy(&id, (char *)pAuthTicket + 0x0c, sizeof(id));
data.id = CSteamID(id);
data.number = number;
} else if (settings->block_unknown_clients) {
PRINT_DEBUG("unrecognized ticket format, rejecting");
return {};
} else if (fallbackID.IsValid()) {
PRINT_DEBUG("unrecognized ticket format");
data.id = fallbackID;
data.number = 0;
} else {
PRINT_DEBUG("unrecognized ticket format and no fallback steam id is provided, rejecting");
return {};
}
data.created = std::chrono::high_resolution_clock::now();
if (pSteamIDUser) *pSteamIDUser = data.id;
return data;
}
EBeginAuthSessionResult Auth_Manager::beginAuth(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID)
{
Auth_Data data = validateTicket(pAuthTicket, cbAuthTicket, steamID, nullptr);
if (!data.id.IsValid() || data.id != steamID)
return k_EBeginAuthSessionResultInvalidTicket;
for (auto & t : inbound) {
if (t.id == data.id && !check_timedout(t.created, STEAM_TICKET_PROCESS_TIME)) {

View File

@@ -122,8 +122,11 @@ bool SteamCallResults::callback_result(SteamAPICall_t api_call, void *copy_to, u
if (cb_result != callresults.end()) {
if (!cb_result->call_completed()) return false;
// Real Steam just does nothing and returns true if nullptr is passed.
if (!copy_to) return true;
// Real Steam just copies nothing and returns true if nullptr is passed.
if (!copy_to) {
cb_result->to_delete = true;
return true;
}
memset(copy_to, 0, size);
@@ -138,7 +141,6 @@ bool SteamCallResults::callback_result(SteamAPICall_t api_call, void *copy_to, u
// This behavior is needed for RemoteStorageFileShareResult_t which was made larger in sdk v1.28x
// without even the interface version being bumped.
size_t outsize = std::min(resultsize, static_cast<size_t>(size));
memcpy(copy_to, cb_result->result.data(), outsize);
cb_result->to_delete = true;
return true;

View File

@@ -7,7 +7,7 @@
#include "base.h"
#include "include.wrap.mbedtls.h"
#define STEAM_TICKET_MIN_SIZE (4 + 8 + 8)
#define STEAM_TICKET_MIN_SIZE (4 + 8 + 8 + 4)
#define STEAM_TICKET_MIN_SIZE_NEW 170
// Steam recommends sending 1024 byte buffer. It returns 234 byte ticket.
@@ -30,6 +30,12 @@ struct AppTicketGC {
uint64_t GCToken{};
CSteamID id{};
uint32_t ticketGenDate{}; //epoch
public:
std::vector<uint8_t> Serialize() const;
};
struct AppTicketSession {
uint32_t ExternalIP{};
uint32_t InternalIP{};
uint32_t TimeSinceStartup{};
@@ -60,7 +66,9 @@ struct AppTicket {
struct Auth_Data {
bool HasGC{};
bool HasSession{};
AppTicketGC GC{};
AppTicketSession Session{};
AppTicket Ticket{};
//old data
CSteamID id{};
@@ -95,6 +103,7 @@ public:
HAuthTicket getWebApiTicket( const char *pchIdentity );
void cancelTicket(uint32 number);
Auth_Data validateTicket(const void *pAuthTicket, uint32 cbAuthTicket, CSteamID fallbackID, CSteamID *pSteamIDUser);
EBeginAuthSessionResult beginAuth(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID);
bool endAuth(CSteamID id);
@@ -105,7 +114,7 @@ public:
CSteamID fakeUser();
Auth_Data getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket );
Auth_Data getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, bool add_session_header = false);
};
#endif // AUTH_INCLUDE_H

View File

@@ -268,9 +268,11 @@ public:
bool steam_deck = false;
// use new app_ticket auth instead of old one
bool enable_new_app_ticket = false;
bool enable_new_app_ticket = true;
// can use GC token for generation
bool use_gc_token = false;
bool use_gc_token = true;
// block connections from clients with unknown auth ticket
bool block_unknown_clients = false;
// allow stats not defined by the user?
bool allow_unknown_stats = false;

View File

@@ -1498,6 +1498,9 @@ static void parse_simple_features(class Settings *settings_client, class Setting
settings_client->use_gc_token = ini.GetBoolValue("main::general", "gc_token", settings_client->use_gc_token);
settings_server->use_gc_token = ini.GetBoolValue("main::general", "gc_token", settings_server->use_gc_token);
settings_client->block_unknown_clients = ini.GetBoolValue("main::general", "block_unknown_clients", settings_client->block_unknown_clients);
settings_server->block_unknown_clients = ini.GetBoolValue("main::general", "block_unknown_clients", settings_server->block_unknown_clients);
settings_client->disable_account_avatar = !ini.GetBoolValue("main::general", "enable_account_avatar", !settings_client->disable_account_avatar);
settings_server->disable_account_avatar = !ini.GetBoolValue("main::general", "enable_account_avatar", !settings_server->disable_account_avatar);

View File

@@ -914,6 +914,7 @@ int Steam_User::CreateAccount( const char *unk1, void *unk2, void *unk3, const c
bool Steam_User::GSSendLogonRequest( CSteamID *steamID )
{
PRINT_DEBUG("%llu", (*steamID).ConvertToUint64());
std::lock_guard<std::recursive_mutex> lock(global_mutex);
// Note that SteamID passed into this comes from Steam.dll so it won't match the client's Goldberg SteamID.
std::pair<CSteamID, std::chrono::high_resolution_clock::time_point> entry(*steamID, std::chrono::high_resolution_clock::now());
@@ -925,6 +926,8 @@ bool Steam_User::GSSendLogonRequest( CSteamID *steamID )
bool Steam_User::GSSendDisconnect( CSteamID *steamID )
{
PRINT_DEBUG("%llu", (*steamID).ConvertToUint64());
std::lock_guard<std::recursive_mutex> lock(global_mutex);
get_steam_client()->steam_gameserver->remove_player(*steamID);
return true;
}

View File

@@ -3,12 +3,15 @@
# ############################################################################## #
[main::general]
# 1=generate newer version of auth ticket, used by some modern apps
# default=0
# 1=generate modern version of auth ticket, may need to be disabled for very old games
# default=1
new_app_ticket=1
# 1=generate/embed Game Coordinator token inside the new auth ticket
# default=0
# default=1
gc_token=1
# 1=game server will only allow connections from legit Steam clients and known Steam emulators
# default=0
block_unknown_clients=0
# 1=pretend the app is running on a steam deck
# default=0
steam_deck=0