aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest/serverauthentication.cpp
blob: 5e27e9a56173c06705f3fa1919c5f397195895f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "pch.h"
#include "serverauthentication.h"
#include "convar.h"
#include "hookutils.h"
#include <fstream>
#include <filesystem>

// hooks
typedef void(*RejectClientType)(void* a1, const char* a2, void* player, const char* fmt, ...);
RejectClientType RejectClient;

typedef void*(*CBaseServer__ConnectClientType)(void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11, void* a12, char a13, char a14, void* a15, uint32_t a16, uint32_t a17);
CBaseServer__ConnectClientType CBaseServer__ConnectClient;

typedef char(*CBaseClient__ConnectType)(void* self, char* name, __int64 netchan_ptr_arg, char b_fake_player_arg, __int64 a5, char* Buffer, int a7);
CBaseClient__ConnectType CBaseClient__Connect;

// global vars
ServerAuthenticationManager* g_ServerAuthenticationManager;

ConVar* CVar_ns_auth_allow_insecure;
ConVar* CVar_ns_auth_allow_insecure_write;

ServerAuthenticationManager::ServerAuthenticationManager() : m_authData(std::unordered_map<std::string, AuthData*>())
{}

void ServerAuthenticationManager::AddPlayerAuth(char* authToken, char* uid, char* pdata, size_t pdataSize)
{
	
}

bool ServerAuthenticationManager::AuthenticatePlayer(__int64 player, char* authToken)
{
	// straight up just given up
	if (!m_authData.empty() && m_authData.count(authToken))
	{
		// use stored auth data
		AuthData* authData = m_authData[authToken];
		
		// uuid
		strcpy((char*)player + 0xF500, authData->uid);

		// copy pdata into buffer
		memcpy((char*)player + 0x4FA, authData->pdata, authData->pdataSize);
	}
	else
	{
		if (!CVar_ns_auth_allow_insecure->m_nValue) // no auth data and insecure connections aren't allowed, so dc the client
			return false;

		spdlog::info("wtf");
		spdlog::info(player);

		// no auth data available and insecure connections are allowed, try reading from disk, using authtoken as uid
		
		// uuid
		strcpy((char*)(player + 0xF500), authToken);

		// try reading pdata file for player
		std::string pdataPath = "playerdata/playerdata_";
		pdataPath += authToken;
		pdataPath += ".pdata";

		std::fstream pdataStream(pdataPath, std::ios_base::in);
		if (pdataStream.fail()) // file doesn't exist, use placeholder
			pdataStream = std::fstream("playerdata/placeholder_playerdata.pdata");
		
		// get file length
		pdataStream.seekg(0, pdataStream.end);
		int length = pdataStream.tellg();
		pdataStream.seekg(0, pdataStream.beg);

		// copy pdata into buffer
		

		pdataStream.read((char*)(player + 0x4FA), length);
	}

	// set persistent data as ready
	*(char*)(player + 0x4a0) = (char)0x3;

	return true; // auth successful, client stays on
}

// store this in a var so we can use it in CBaseClient::Connect
// this is fine because serverfilter ptr won't decay by the time we use this
char* nextPlayerToken;

void* CBaseServer__ConnectClientHook(void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11, void* a12, char a13, char a14, void* a15, uint32_t a16, uint32_t a17)
{
	// auth tokens are sent with serverfilter, can't be accessed from player struct to my knowledge, so have to do this here
	nextPlayerToken = serverFilter;

	return CBaseServer__ConnectClient(server, a2, a3, a4, a5, a6, a7, a8, serverFilter, a10, a11, a12, a13, a14, a15, a16, a17);
}

char CBaseClient__ConnectHook(void* self, char* name, __int64 netchan_ptr_arg, char b_fake_player_arg, __int64 a5, char* Buffer, int a7)
{
	if (!g_ServerAuthenticationManager->AuthenticatePlayer((__int64)self, nextPlayerToken))
	{
		//RejectClient(nullptr, "Authentication failed", self, "Authentication failed");
		//return 0;
	}

	return CBaseClient__Connect(self, name, netchan_ptr_arg, b_fake_player_arg, a5, Buffer, a7);
}

void InitialiseServerAuthentication(HMODULE baseAddress)
{
	g_ServerAuthenticationManager = new ServerAuthenticationManager;

	RejectClient = (RejectClientType)((char*)baseAddress + 0x1182E0);

	CVar_ns_auth_allow_insecure = RegisterConVar("ns_auth_allow_insecure", "0", FCVAR_GAMEDLL, "Whether this server will allow unauthenicated players to connect");
	CVar_ns_auth_allow_insecure_write = RegisterConVar("ns_auth_allow_insecure_write", "0", FCVAR_GAMEDLL, "Whether the pdata of unauthenticated clients will be written to disk when changed");

	spdlog::info((void*)CVar_ns_auth_allow_insecure);
	spdlog::info((void*)&CVar_ns_auth_allow_insecure->m_nValue);

	HookEnabler hook;
	ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x114430, &CBaseServer__ConnectClientHook, reinterpret_cast<LPVOID*>(&CBaseServer__ConnectClient));
	ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x101740, &CBaseClient__ConnectHook, reinterpret_cast<LPVOID*>(&CBaseClient__Connect));

	// patch to disable kicking based on incorrect serverfilter in connectclient, since we repurpose it for use as an auth token
	{
		void* ptr = (char*)baseAddress + 0x114655;
		TempReadWrite rw(ptr);
		*((char*)ptr) = (char)0xEB; // jz => jmp
	}
}