Index: ps/trunk/source/network/NMTCreator.h =================================================================== --- ps/trunk/source/network/NMTCreator.h +++ ps/trunk/source/network/NMTCreator.h @@ -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 @@ #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 _nm; \ @@ -155,6 +163,9 @@ #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 @@ #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 @@ #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 @@ 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); \ } Index: ps/trunk/source/network/NetClient.h =================================================================== --- ps/trunk/source/network/NetClient.h +++ ps/trunk/source/network/NetClient.h @@ -100,6 +100,11 @@ 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 @@ 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; Index: ps/trunk/source/network/NetClient.cpp =================================================================== --- ps/trunk/source/network/NetClient.cpp +++ ps/trunk/source/network/NetClient.cpp @@ -175,6 +175,11 @@ 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 @@ { CAuthenticateMessage authenticate; authenticate.m_Name = m_UserName; - authenticate.m_Password = L""; // TODO + authenticate.m_Password = m_Password; authenticate.m_IsLocalClient = m_IsLocalClient; SendMessage(&authenticate); } Index: ps/trunk/source/network/NetMessages.h =================================================================== --- ps/trunk/source/network/NetMessages.h +++ ps/trunk/source/network/NetMessages.h @@ -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 @@ 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() Index: ps/trunk/source/network/NetServer.h =================================================================== --- ps/trunk/source/network/NetServer.h +++ ps/trunk/source/network/NetServer.h @@ -209,6 +209,8 @@ 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 @@ std::vector m_BannedIPs; std::vector m_BannedPlayers; + CStr m_Password; + /** * Holds the GUIDs of all currently paused players. */ Index: ps/trunk/source/network/NetServer.cpp =================================================================== --- ps/trunk/source/network/NetServer.cpp +++ ps/trunk/source/network/NetServer.cpp @@ -181,6 +181,11 @@ 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 @@ 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 @@ return true; } - // TODO: check server password etc? - u32 newHostID = server.m_NextHostID++; session->SetUserName(username); @@ -1622,6 +1637,8 @@ void CNetServer::SetPassword(const CStr& password) { m_Password = password; + std::lock_guard lock(m_Worker->m_WorkerMutex); + m_Worker->SetPassword(password); } void CNetServer::StartGame() Index: ps/trunk/source/network/NetSession.h =================================================================== --- ps/trunk/source/network/NetSession.h +++ ps/trunk/source/network/NetSession.h @@ -225,6 +225,7 @@ CStr m_GUID; CStrW m_UserName; u32 m_HostID; + CStr m_Password; bool m_IsLocalClient; }; Index: ps/trunk/source/network/scripting/JSInterface_Network.cpp =================================================================== --- ps/trunk/source/network/scripting/JSInterface_Network.cpp +++ ps/trunk/source/network/scripting/JSInterface_Network.cpp @@ -128,12 +128,14 @@ } // 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 @@ 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))