Net Server: Verify password in Authenticate
Follows 1a8de6d2b8
.
Validate the password when a client joins a game, so even a player that
knows the connection data cannot join.
Refs #3556, Refs #5913
Differential Revision: https://code.wildfiregames.com/D3438
This was SVN commit r24775.
This commit is contained in:
parent
498f5eb083
commit
4cc824d620
@ -29,6 +29,7 @@
|
||||
#undef START_NMT_CLASS_DERIVED
|
||||
#undef NMT_FIELD_INT
|
||||
#undef NMT_FIELD
|
||||
#undef NMT_FIELD_SECRET
|
||||
#undef NMT_START_ARRAY
|
||||
#undef NMT_END_ARRAY
|
||||
#undef END_NMT_CLASS
|
||||
@ -106,6 +107,13 @@ public: \
|
||||
#define NMT_FIELD(_tp, _nm) \
|
||||
_tp _nm;
|
||||
|
||||
/**
|
||||
* Likewise, but the string representation is hidden.
|
||||
* NB: the data length is not hidden, so make sure to use fixed-length data if confidentiality is desirable.
|
||||
*/
|
||||
#define NMT_FIELD_SECRET(_tp, _nm) \
|
||||
_tp _nm;
|
||||
|
||||
#define NMT_START_ARRAY(_nm) \
|
||||
struct ARRAY_STRUCT_PREFIX(_nm); \
|
||||
std::vector <ARRAY_STRUCT_PREFIX(_nm)> _nm; \
|
||||
@ -155,6 +163,9 @@ size_t _nm::GetSerializedLength() const \
|
||||
#define NMT_FIELD(_tp, _nm) \
|
||||
ret += thiz->_nm.GetSerializedLength();
|
||||
|
||||
#define NMT_FIELD_SECRET(_tp, _nm) \
|
||||
ret += thiz->_nm.GetSerializedLength();
|
||||
|
||||
#define END_NMT_CLASS() \
|
||||
return ret; \
|
||||
};
|
||||
@ -197,6 +208,9 @@ u8 *_nm::Serialize(u8 *buffer) const \
|
||||
#define NMT_FIELD(_tp, _nm) \
|
||||
pos=thiz->_nm.Serialize(pos);
|
||||
|
||||
#define NMT_FIELD_SECRET(_tp, _nm) \
|
||||
pos=thiz->_nm.Serialize(pos);
|
||||
|
||||
#define END_NMT_CLASS() \
|
||||
return pos; \
|
||||
}
|
||||
@ -244,6 +258,9 @@ const u8 *_nm::Deserialize(const u8 *pos, const u8 *end) \
|
||||
#define NMT_FIELD(_tp, _nm) \
|
||||
if ((pos=thiz->_nm.Deserialize(pos, end)) == NULL) BAIL_DESERIALIZER;
|
||||
|
||||
#define NMT_FIELD_SECRET(_tp, _nm) \
|
||||
if ((pos=thiz->_nm.Deserialize(pos, end)) == NULL) BAIL_DESERIALIZER;
|
||||
|
||||
#define END_NMT_CLASS() \
|
||||
return pos; \
|
||||
}
|
||||
@ -309,6 +326,9 @@ CStr _nm::ToStringRaw() const \
|
||||
ret += NetMessageStringConvert(thiz->_nm); \
|
||||
ret += ", ";
|
||||
|
||||
#define NMT_FIELD_SECRET(_tp, _nm) \
|
||||
ret += #_nm ": [secret], ";
|
||||
|
||||
#define END_NMT_CLASS() \
|
||||
return ret.substr(0, ret.length()-2); \
|
||||
}
|
||||
|
@ -175,6 +175,11 @@ void CNetClient::SetHostingPlayerName(const CStr& hostingPlayerName)
|
||||
m_HostingPlayerName = hostingPlayerName;
|
||||
}
|
||||
|
||||
void CNetClient::SetGamePassword(const CStr& hashedPassword)
|
||||
{
|
||||
m_Password = hashedPassword;
|
||||
}
|
||||
|
||||
bool CNetClient::SetupConnection(ENetHost* enetClient)
|
||||
{
|
||||
CNetClientSession* session = new CNetClientSession(*this);
|
||||
@ -570,7 +575,7 @@ void CNetClient::SendAuthenticateMessage()
|
||||
{
|
||||
CAuthenticateMessage authenticate;
|
||||
authenticate.m_Name = m_UserName;
|
||||
authenticate.m_Password = L""; // TODO
|
||||
authenticate.m_Password = m_Password;
|
||||
authenticate.m_IsLocalClient = m_IsLocalClient;
|
||||
SendMessage(&authenticate);
|
||||
}
|
||||
|
@ -99,6 +99,11 @@ public:
|
||||
*/
|
||||
void SetHostingPlayerName(const CStr& hostingPlayerName);
|
||||
|
||||
/**
|
||||
* Set the game password.
|
||||
*/
|
||||
void SetGamePassword(const CStr& hashedPassword);
|
||||
|
||||
/**
|
||||
* Returns the GUID of the local client.
|
||||
* Used for distinguishing observers.
|
||||
@ -293,6 +298,11 @@ private:
|
||||
u16 m_ServerPort;
|
||||
bool m_UseSTUN;
|
||||
|
||||
/**
|
||||
* Password to join the game.
|
||||
*/
|
||||
CStr m_Password;
|
||||
|
||||
/// Current network session (or NULL if not connected)
|
||||
CNetClientSession* m_Session;
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
|
||||
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
|
||||
#define PS_PROTOCOL_VERSION 0x01010015 // Arbitrary protocol
|
||||
#define PS_PROTOCOL_VERSION 0x01010016 // Arbitrary protocol
|
||||
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
|
||||
|
||||
// Set when lobby authentication is required. Used in the SrvHandshakeResponseMessage.
|
||||
@ -121,8 +121,7 @@ END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Authenticate, NMT_AUTHENTICATE)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
// TODO: The password should not be printed to logfiles
|
||||
NMT_FIELD(CStrW, m_Password)
|
||||
NMT_FIELD_SECRET(CStr, m_Password)
|
||||
NMT_FIELD_INT(m_IsLocalClient, u8, 1)
|
||||
END_NMT_CLASS()
|
||||
|
||||
|
@ -181,6 +181,11 @@ CNetServerWorker::~CNetServerWorker()
|
||||
delete m_ServerTurnManager;
|
||||
}
|
||||
|
||||
void CNetServerWorker::SetPassword(const CStr& hashedPassword)
|
||||
{
|
||||
m_Password = hashedPassword;
|
||||
}
|
||||
|
||||
bool CNetServerWorker::SetupConnection(const u16 port)
|
||||
{
|
||||
ENSURE(m_State == SERVER_STATE_UNCONNECTED);
|
||||
@ -979,6 +984,18 @@ bool CNetServerWorker::OnAuthenticate(void* context, CFsmEvent* event)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the password before anything else.
|
||||
if (server.m_Password != message->m_Password)
|
||||
{
|
||||
// Noisy logerror because players are not supposed to be able to get the IP,
|
||||
// so this might be someone targeting the host for some reason
|
||||
// (or TODO a dedicated server and we do want to log anyways)
|
||||
LOGERROR("Net server: user %s tried joining with the wrong password",
|
||||
session->GetUserName().ToUTF8());
|
||||
session->Disconnect(NDR_SERVER_REFUSED);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Either deduplicate or prohibit join if name is in use
|
||||
bool duplicatePlayernames = false;
|
||||
CFG_GET_VAL("network.duplicateplayernames", duplicatePlayernames);
|
||||
@ -1088,8 +1105,6 @@ bool CNetServerWorker::OnAuthenticate(void* context, CFsmEvent* event)
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: check server password etc?
|
||||
|
||||
u32 newHostID = server.m_NextHostID++;
|
||||
|
||||
session->SetUserName(username);
|
||||
@ -1622,6 +1637,8 @@ bool CNetServer::CheckPassword(const CStr& password) const
|
||||
void CNetServer::SetPassword(const CStr& password)
|
||||
{
|
||||
m_Password = password;
|
||||
std::lock_guard<std::mutex> lock(m_Worker->m_WorkerMutex);
|
||||
m_Worker->SetPassword(password);
|
||||
}
|
||||
|
||||
void CNetServer::StartGame()
|
||||
|
@ -209,6 +209,8 @@ private:
|
||||
CNetServerWorker(bool useLobbyAuth, int autostartPlayers);
|
||||
~CNetServerWorker();
|
||||
|
||||
void SetPassword(const CStr& hashedPassword);
|
||||
|
||||
/**
|
||||
* Begin listening for network connections.
|
||||
* @return true on success, false on error (e.g. port already in use)
|
||||
@ -341,6 +343,8 @@ private:
|
||||
std::vector<u32> m_BannedIPs;
|
||||
std::vector<CStrW> m_BannedPlayers;
|
||||
|
||||
CStr m_Password;
|
||||
|
||||
/**
|
||||
* Holds the GUIDs of all currently paused players.
|
||||
*/
|
||||
|
@ -225,6 +225,7 @@ private:
|
||||
CStr m_GUID;
|
||||
CStrW m_UserName;
|
||||
u32 m_HostID;
|
||||
CStr m_Password;
|
||||
|
||||
bool m_IsLocalClient;
|
||||
};
|
||||
|
@ -128,12 +128,14 @@ void JSI_Network::StartNetworkHost(ScriptInterface::CmptPrivate* pCmptPrivate, c
|
||||
}
|
||||
|
||||
// We will get hashed password from clients, so hash it once for server
|
||||
g_NetServer->SetPassword(HashPassword(password));
|
||||
CStr hashedPass = HashPassword(password);
|
||||
g_NetServer->SetPassword(hashedPass);
|
||||
|
||||
g_Game = new CGame(true);
|
||||
g_NetClient = new CNetClient(g_Game, true);
|
||||
g_NetClient->SetUserName(playerName);
|
||||
g_NetClient->SetHostingPlayerName(hostLobbyName);
|
||||
g_NetClient->SetGamePassword(hashedPass);
|
||||
g_NetClient->SetupServerData("127.0.0.1", serverPort, false);
|
||||
|
||||
if (!g_NetClient->SetupConnection(nullptr))
|
||||
@ -173,11 +175,13 @@ void JSI_Network::StartNetworkJoinLobby(ScriptInterface::CmptPrivate* pCmptPriva
|
||||
ENSURE(!g_NetServer);
|
||||
ENSURE(!g_Game);
|
||||
|
||||
CStr hashedPass = HashPassword(password);
|
||||
g_Game = new CGame(true);
|
||||
g_NetClient = new CNetClient(g_Game, false);
|
||||
g_NetClient->SetUserName(playerName);
|
||||
g_NetClient->SetHostingPlayerName(hostJID.substr(0, hostJID.find("@")));
|
||||
g_XmppClient->SendIqGetConnectionData(hostJID, HashPassword(password).c_str());
|
||||
g_NetClient->SetGamePassword(hashedPass);
|
||||
g_XmppClient->SendIqGetConnectionData(hostJID, hashedPass.c_str());
|
||||
}
|
||||
|
||||
void JSI_Network::DisconnectNetworkGame(ScriptInterface::CmptPrivate* UNUSED(pCmptPrivate))
|
||||
|
Loading…
Reference in New Issue
Block a user