mirror of https://github.com/OpenTTD/OpenTTD.git
Feature: authenticate to the server without sending the password
Either using password-authentication key exchange or via authorized keys
This commit is contained in:
parent
dd532cbc77
commit
5706801ea7
|
@ -2574,6 +2574,7 @@ STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Your pla
|
|||
STR_NETWORK_ERROR_BAD_SERVER_NAME :{WHITE}Your server name has not been set. The name can be set at the top of the Multiplayer window
|
||||
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision
|
||||
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password
|
||||
STR_NETWORK_ERROR_NOT_ON_ALLOW_LIST :{WHITE}You are not on the list of allowed clients
|
||||
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full
|
||||
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server
|
||||
STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game
|
||||
|
@ -2589,7 +2590,7 @@ STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Your pla
|
|||
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss
|
||||
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}The last {NUM} second{P "" s} no data has arrived from the server
|
||||
|
||||
###length 21
|
||||
###length 22
|
||||
STR_NETWORK_ERROR_CLIENT_GENERAL :general error
|
||||
STR_NETWORK_ERROR_CLIENT_DESYNC :desync error
|
||||
STR_NETWORK_ERROR_CLIENT_SAVEGAME :could not load map
|
||||
|
@ -2601,6 +2602,7 @@ STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :received invali
|
|||
STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :wrong revision
|
||||
STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :name already in use
|
||||
STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :wrong password
|
||||
STR_NETWORK_ERROR_CLIENT_NOT_ON_ALLOW_LIST :not on allow list
|
||||
STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :wrong company in DoCommand
|
||||
STR_NETWORK_ERROR_CLIENT_KICKED :kicked by server
|
||||
STR_NETWORK_ERROR_CLIENT_CHEATER :was trying to use a cheat
|
||||
|
|
|
@ -82,9 +82,10 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet &p)
|
|||
case PACKET_SERVER_GAME_INFO: return this->Receive_SERVER_GAME_INFO(p);
|
||||
case PACKET_SERVER_CLIENT_INFO: return this->Receive_SERVER_CLIENT_INFO(p);
|
||||
case PACKET_CLIENT_IDENTIFY: return this->Receive_CLIENT_IDENTIFY(p);
|
||||
case PACKET_SERVER_NEED_GAME_PASSWORD: return this->Receive_SERVER_NEED_GAME_PASSWORD(p);
|
||||
case PACKET_SERVER_AUTH_REQUEST: return this->Receive_SERVER_AUTH_REQUEST(p);
|
||||
case PACKET_SERVER_NEED_COMPANY_PASSWORD: return this->Receive_SERVER_NEED_COMPANY_PASSWORD(p);
|
||||
case PACKET_CLIENT_GAME_PASSWORD: return this->Receive_CLIENT_GAME_PASSWORD(p);
|
||||
case PACKET_CLIENT_AUTH_RESPONSE: return this->Receive_CLIENT_AUTH_RESPONSE(p);
|
||||
case PACKET_SERVER_AUTH_COMPLETED: return this->Receive_SERVER_AUTH_COMPLETED(p);
|
||||
case PACKET_CLIENT_COMPANY_PASSWORD: return this->Receive_CLIENT_COMPANY_PASSWORD(p);
|
||||
case PACKET_SERVER_WELCOME: return this->Receive_SERVER_WELCOME(p);
|
||||
case PACKET_CLIENT_GETMAP: return this->Receive_CLIENT_GETMAP(p);
|
||||
|
@ -164,9 +165,10 @@ NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_INFO(Packet &) {
|
|||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_CLIENT_INFO); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_IDENTIFY); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_GAME_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_AUTH_REQUEST(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_AUTH_REQUEST); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_AUTH_RESPONSE(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_AUTH_RESPONSE); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_AUTH_COMPLETED(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_AUTH_COMPLETED); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); }
|
||||
NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet &) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); }
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "os_abstraction.h"
|
||||
#include "tcp.h"
|
||||
#include "../network_type.h"
|
||||
#include "../network_crypto.h"
|
||||
#include "../../core/pool_type.hpp"
|
||||
#include <chrono>
|
||||
|
||||
|
@ -56,16 +57,19 @@ enum PacketGameType : uint8_t {
|
|||
* the map and other important data.
|
||||
*/
|
||||
|
||||
/* After the initial join, the next step is identification. */
|
||||
/* After the join step, the first perform game authentication and enabling encryption. */
|
||||
PACKET_SERVER_AUTH_REQUEST, ///< The server requests the client to authenticate using a number of methods.
|
||||
PACKET_CLIENT_AUTH_RESPONSE, ///< The client responds to the authentication request.
|
||||
PACKET_SERVER_AUTH_COMPLETED, ///< The server indicates the authentication is completed.
|
||||
|
||||
/* After the authentication is done, the next step is identification. */
|
||||
PACKET_CLIENT_IDENTIFY, ///< Client telling the server the client's name and requested company.
|
||||
|
||||
/* After the identify step, the next is checking NewGRFs. */
|
||||
PACKET_SERVER_CHECK_NEWGRFS, ///< Server sends NewGRF IDs and MD5 checksums for the client to check.
|
||||
PACKET_CLIENT_NEWGRFS_CHECKED, ///< Client acknowledges that it has all required NewGRFs.
|
||||
|
||||
/* Checking the game, and then company passwords. */
|
||||
PACKET_SERVER_NEED_GAME_PASSWORD, ///< Server requests the (hashed) game password.
|
||||
PACKET_CLIENT_GAME_PASSWORD, ///< Clients sends the (hashed) game password.
|
||||
/* Checking the company passwords. */
|
||||
PACKET_SERVER_NEED_COMPANY_PASSWORD, ///< Server requests the (hashed) company password.
|
||||
PACKET_CLIENT_COMPANY_PASSWORD, ///< Client sends the (hashed) company password.
|
||||
|
||||
|
@ -214,10 +218,13 @@ protected:
|
|||
virtual NetworkRecvStatus Receive_CLIENT_IDENTIFY(Packet &p);
|
||||
|
||||
/**
|
||||
* Indication to the client that the server needs a game password.
|
||||
* Indication to the client that it needs to authenticate:
|
||||
* bool Whether to use the password in the key exchange.
|
||||
* 32 * uint8_t Public key of the server.
|
||||
* 24 * uint8_t Nonce for the key exchange.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet &p);
|
||||
virtual NetworkRecvStatus Receive_SERVER_AUTH_REQUEST(Packet &p);
|
||||
|
||||
/**
|
||||
* Indication to the client that the server needs a company password:
|
||||
|
@ -228,12 +235,19 @@ protected:
|
|||
virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p);
|
||||
|
||||
/**
|
||||
* Send a password to the server to authorize:
|
||||
* uint8_t Password type (see NetworkPasswordType).
|
||||
* string The password.
|
||||
* Send the response to the authentication request:
|
||||
* 32 * uint8_t Public key of the client.
|
||||
* 8 * uint8_t Random message that got encoded and signed.
|
||||
* 16 * uint8_t Message authentication code.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet &p);
|
||||
virtual NetworkRecvStatus Receive_CLIENT_AUTH_RESPONSE(Packet &p);
|
||||
|
||||
/**
|
||||
* Indication to the client that authentication has completed.
|
||||
* @param p The packet that was just received.
|
||||
*/
|
||||
virtual NetworkRecvStatus Receive_SERVER_AUTH_COMPLETED(Packet &p);
|
||||
|
||||
/**
|
||||
* Send a password to the server to authorize
|
||||
|
|
|
@ -321,6 +321,7 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err)
|
|||
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP,
|
||||
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN,
|
||||
STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME,
|
||||
STR_NETWORK_ERROR_CLIENT_NOT_ON_ALLOW_LIST,
|
||||
};
|
||||
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin()
|
|||
p->Send_uint32(_openttd_newgrf_version);
|
||||
my_client->SendPacket(std::move(p));
|
||||
|
||||
return ClientNetworkGameSocketHandler::SendIdentify();
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendIdentify()
|
||||
|
@ -377,13 +377,14 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
|||
* Set the game password as requested.
|
||||
* @param password The game password.
|
||||
*/
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const std::string &password)
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendAuthResponse()
|
||||
{
|
||||
Debug(net, 9, "Client::SendGamePassword()");
|
||||
Debug(net, 9, "Client::SendAuthResponse()");
|
||||
|
||||
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_GAME_PASSWORD);
|
||||
p->Send_string(password);
|
||||
auto p = std::make_unique<Packet>(my_client, PACKET_CLIENT_AUTH_RESPONSE);
|
||||
my_client->authentication_handler->SendResponse(*p);
|
||||
my_client->SendPacket(std::move(p));
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
|
@ -680,6 +681,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p
|
|||
STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP
|
||||
STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN
|
||||
STR_NETWORK_ERROR_INVALID_CLIENT_NAME, // NETWORK_ERROR_INVALID_CLIENT_NAME
|
||||
STR_NETWORK_ERROR_NOT_ON_ALLOW_LIST, // NETWORK_ERROR_NOT_ON_ALLOW_LIST
|
||||
};
|
||||
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||
|
||||
|
@ -705,7 +707,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p
|
|||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->status != STATUS_AUTHENTICATED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
uint grf_count = p.Recv_uint8();
|
||||
NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY;
|
||||
|
@ -736,26 +738,67 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P
|
|||
return ret;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet &)
|
||||
class ClientGamePasswordRequestHandler : public NetworkAuthenticationPasswordRequestHandler {
|
||||
virtual void SendResponse() override { MyClient::SendAuthResponse(); }
|
||||
virtual void AskUserForPassword(std::shared_ptr<NetworkAuthenticationPasswordRequest> request) override
|
||||
{
|
||||
if (!_network_join.server_password.empty()) {
|
||||
request->Reply(_network_join.server_password);
|
||||
} else {
|
||||
ShowNetworkNeedPassword(NETWORK_GAME_PASSWORD, request);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_AUTH_REQUEST(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->status != STATUS_JOIN && this->status != STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
Debug(net, 9, "Client::status = AUTH_GAME");
|
||||
this->status = STATUS_AUTH_GAME;
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_NEED_GAME_PASSWORD()");
|
||||
Debug(net, 9, "Client::Receive_SERVER_AUTH_REQUEST()");
|
||||
|
||||
if (!_network_join.server_password.empty()) {
|
||||
return SendGamePassword(_network_join.server_password);
|
||||
if (this->authentication_handler == nullptr) {
|
||||
this->authentication_handler = NetworkAuthenticationClientHandler::Create(std::make_shared<ClientGamePasswordRequestHandler>(),
|
||||
_settings_client.network.client_secret_key, _settings_client.network.client_public_key);
|
||||
}
|
||||
switch (this->authentication_handler->ReceiveRequest(p)) {
|
||||
case NetworkAuthenticationClientHandler::READY_FOR_RESPONSE:
|
||||
return SendAuthResponse();
|
||||
|
||||
ShowNetworkNeedPassword(NETWORK_GAME_PASSWORD);
|
||||
|
||||
case NetworkAuthenticationClientHandler::AWAIT_USER_INPUT:
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
case NetworkAuthenticationClientHandler::INVALID:
|
||||
default:
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_AUTH_COMPLETED(Packet &)
|
||||
{
|
||||
if (this->status != STATUS_AUTH_GAME || this->authentication_handler == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
|
||||
Debug(net, 9, "Client::Receive_SERVER_AUTH_COMPLETED()");
|
||||
|
||||
this->authentication_handler = nullptr;
|
||||
|
||||
Debug(net, 9, "Client::status = AUTHENTICATED");
|
||||
this->status = STATUS_AUTHENTICATED;
|
||||
|
||||
return this->SendIdentify();
|
||||
}
|
||||
|
||||
class CompanyPasswordRequest : public NetworkAuthenticationPasswordRequest {
|
||||
virtual void Reply(const std::string &password) override
|
||||
{
|
||||
MyClient::SendCompanyPassword(password);
|
||||
}
|
||||
};
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->status < STATUS_AUTHENTICATED || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
Debug(net, 9, "Client::status = AUTH_COMPANY");
|
||||
this->status = STATUS_AUTH_COMPANY;
|
||||
|
||||
|
@ -769,14 +812,14 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA
|
|||
return SendCompanyPassword(_network_join.company_password);
|
||||
}
|
||||
|
||||
ShowNetworkNeedPassword(NETWORK_COMPANY_PASSWORD);
|
||||
ShowNetworkNeedPassword(NETWORK_COMPANY_PASSWORD, std::make_shared<CompanyPasswordRequest>());
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet &p)
|
||||
{
|
||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
if (this->status < STATUS_AUTHENTICATED || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
Debug(net, 9, "Client::status = AUTHORIZED");
|
||||
this->status = STATUS_AUTHORIZED;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
/** Class for handling the client side of the game connection. */
|
||||
class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public NetworkGameSocketHandler {
|
||||
private:
|
||||
std::unique_ptr<class NetworkAuthenticationClientHandler> authentication_handler; ///< The handler for the authentication.
|
||||
std::string connection_string; ///< Address we are connected to.
|
||||
std::shared_ptr<struct PacketReader> savegame; ///< Packet reader for reading the savegame.
|
||||
uint8_t token; ///< The token we need to send back to the server to prove we're the right client.
|
||||
|
@ -23,8 +24,9 @@ private:
|
|||
enum ServerStatus {
|
||||
STATUS_INACTIVE, ///< The client is not connected nor active.
|
||||
STATUS_JOIN, ///< We are trying to join a server.
|
||||
STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs.
|
||||
STATUS_AUTH_GAME, ///< Last action was requesting game (server) password.
|
||||
STATUS_AUTHENTICATED, ///< The game authentication has completed.
|
||||
STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs.
|
||||
STATUS_AUTH_COMPANY, ///< Last action was requesting company password.
|
||||
STATUS_AUTHORIZED, ///< The client is authorized at the server.
|
||||
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
||||
|
@ -44,7 +46,8 @@ protected:
|
|||
NetworkRecvStatus Receive_SERVER_BANNED(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_ERROR(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_AUTH_REQUEST(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_AUTH_COMPLETED(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WELCOME(Packet &p) override;
|
||||
NetworkRecvStatus Receive_SERVER_WAIT(Packet &p) override;
|
||||
|
@ -86,7 +89,7 @@ public:
|
|||
static NetworkRecvStatus SendQuit();
|
||||
static NetworkRecvStatus SendAck();
|
||||
|
||||
static NetworkRecvStatus SendGamePassword(const std::string &password);
|
||||
static NetworkRecvStatus SendAuthResponse();
|
||||
static NetworkRecvStatus SendCompanyPassword(const std::string &password);
|
||||
|
||||
static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const std::string &msg, int64_t data);
|
||||
|
|
|
@ -2103,7 +2103,7 @@ uint32_t _network_join_bytes; ///< The number of bytes we already do
|
|||
uint32_t _network_join_bytes_total; ///< The total number of bytes to download.
|
||||
|
||||
struct NetworkJoinStatusWindow : Window {
|
||||
NetworkPasswordType password_type;
|
||||
std::shared_ptr<NetworkAuthenticationPasswordRequest> request;
|
||||
|
||||
NetworkJoinStatusWindow(WindowDesc *desc) : Window(desc)
|
||||
{
|
||||
|
@ -2199,16 +2199,12 @@ struct NetworkJoinStatusWindow : Window {
|
|||
|
||||
void OnQueryTextFinished(char *str) override
|
||||
{
|
||||
if (StrEmpty(str)) {
|
||||
if (StrEmpty(str) || this->request == nullptr) {
|
||||
NetworkDisconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this->password_type) {
|
||||
case NETWORK_GAME_PASSWORD: MyClient::SendGamePassword (str); break;
|
||||
case NETWORK_COMPANY_PASSWORD: MyClient::SendCompanyPassword(str); break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
this->request->Reply(str);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2236,11 +2232,11 @@ void ShowJoinStatusWindow()
|
|||
new NetworkJoinStatusWindow(&_network_join_status_window_desc);
|
||||
}
|
||||
|
||||
void ShowNetworkNeedPassword(NetworkPasswordType npt)
|
||||
void ShowNetworkNeedPassword(NetworkPasswordType npt, std::shared_ptr<NetworkAuthenticationPasswordRequest> request)
|
||||
{
|
||||
NetworkJoinStatusWindow *w = (NetworkJoinStatusWindow *)FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN);
|
||||
if (w == nullptr) return;
|
||||
w->password_type = npt;
|
||||
w->request = request;
|
||||
|
||||
StringID caption;
|
||||
switch (npt) {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "network_type.h"
|
||||
#include "network_gamelist.h"
|
||||
|
||||
void ShowNetworkNeedPassword(NetworkPasswordType npt);
|
||||
void ShowNetworkNeedPassword(NetworkPasswordType npt, std::shared_ptr<class NetworkAuthenticationPasswordRequest> request);
|
||||
void ShowNetworkChatQueryWindow(DestType type, int dest);
|
||||
void ShowJoinStatusWindow();
|
||||
void ShowNetworkGameWindow();
|
||||
|
|
|
@ -58,6 +58,10 @@ INSTANTIATE_POOL_METHODS(NetworkClientSocket)
|
|||
/** Instantiate the listen sockets. */
|
||||
template SocketList TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED>::sockets;
|
||||
|
||||
static NetworkAuthenticationDefaultPasswordProvider _password_provider(_settings_client.network.server_password); ///< Provides the password validation for the game's password.
|
||||
static NetworkAuthenticationDefaultAuthorizedKeyHandler _authorized_key_handler(_settings_client.network.server_authorized_keys); ///< Provides the authorized key handling for the game authentication.
|
||||
|
||||
|
||||
/** Writing a savegame directly to a number of packets. */
|
||||
struct PacketWriter : SaveFilter {
|
||||
ServerNetworkGameSocketHandler *cs; ///< Socket we are associated with.
|
||||
|
@ -407,8 +411,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
|||
this->status = STATUS_NEWGRFS_CHECK;
|
||||
|
||||
if (_grfconfig == nullptr) {
|
||||
/* There are no NewGRFs, continue with the game password. */
|
||||
return this->SendNeedGamePassword();
|
||||
/* There are no NewGRFs, continue with the company password. */
|
||||
return this->SendNeedCompanyPassword();
|
||||
}
|
||||
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_CHECK_NEWGRFS, TCP_MTU);
|
||||
|
@ -429,25 +433,39 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
|||
}
|
||||
|
||||
/** Request the game password. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendAuthRequest()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendNeedGamePassword()", this->client_id);
|
||||
Debug(net, 9, "client[{}] SendAuthRequest()", this->client_id);
|
||||
|
||||
/* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
|
||||
if (this->status != STATUS_NEWGRFS_CHECK) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
/* Invalid packet when status is anything but STATUS_INACTIVE or STATUS_AUTH_GAME. */
|
||||
if (this->status != STATUS_INACTIVE && status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
Debug(net, 9, "client[{}] status = AUTH_GAME", this->client_id);
|
||||
this->status = STATUS_AUTH_GAME;
|
||||
|
||||
if (_settings_client.network.server_password.empty()) {
|
||||
/* Do not actually need a game password, continue with the company password. */
|
||||
return this->SendNeedCompanyPassword();
|
||||
}
|
||||
|
||||
/* Reset 'lag' counters */
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_NEED_GAME_PASSWORD);
|
||||
if (this->authentication_handler == nullptr) {
|
||||
this->authentication_handler = NetworkAuthenticationServerHandler::Create(&_password_provider, &_authorized_key_handler);
|
||||
}
|
||||
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_AUTH_REQUEST);
|
||||
this->authentication_handler->SendRequest(*p);
|
||||
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/** Notify the client that the authentication has completed. */
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::SendAuthCompleted()
|
||||
{
|
||||
Debug(net, 9, "client[{}] SendAuthCompleted()", this->client_id);
|
||||
|
||||
/* Invalid packet when status is anything but STATUS_AUTH_GAME. */
|
||||
if (this->status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
auto p = std::make_unique<Packet>(this, PACKET_SERVER_AUTH_COMPLETED);
|
||||
this->SendPacket(std::move(p));
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
@ -457,8 +475,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword()
|
|||
{
|
||||
Debug(net, 9, "client[{}] SendNeedCompanyPassword()", this->client_id);
|
||||
|
||||
/* Invalid packet when status is anything but STATUS_AUTH_GAME. */
|
||||
if (this->status != STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
/* Invalid packet when status is anything but STATUS_NEWGRFS_CHECK. */
|
||||
if (this->status != STATUS_NEWGRFS_CHECK) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET);
|
||||
|
||||
Debug(net, 9, "client[{}] status = AUTH_COMPANY", this->client_id);
|
||||
this->status = STATUS_AUTH_COMPANY;
|
||||
|
@ -865,7 +883,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED
|
|||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_NEWGRFS_CHECKED()", this->client_id);
|
||||
|
||||
return this->SendNeedGamePassword();
|
||||
return this->SendNeedCompanyPassword();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
||||
|
@ -891,13 +909,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet &p)
|
|||
return this->SendError(NETWORK_ERROR_WRONG_REVISION);
|
||||
}
|
||||
|
||||
Debug(net, 9, "client[{}] status = IDENTIFY", this->client_id);
|
||||
this->status = STATUS_IDENTIFY;
|
||||
|
||||
/* Reset 'lag' counters */
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
return this->SendAuthRequest();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet &p)
|
||||
|
@ -953,24 +965,52 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet
|
|||
return this->SendNewGRFCheck();
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet &p)
|
||||
static NetworkErrorCode GetErrorForAuthenticationMethod(NetworkAuthenticationMethod method)
|
||||
{
|
||||
switch (method) {
|
||||
case NETWORK_AUTH_METHOD_X25519_PAKE:
|
||||
return NETWORK_ERROR_WRONG_PASSWORD;
|
||||
case NETWORK_AUTH_METHOD_X25519_AUTHORIZED_KEY:
|
||||
return NETWORK_ERROR_NOT_ON_ALLOW_LIST;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_AUTH_RESPONSE(Packet &p)
|
||||
{
|
||||
if (this->status != STATUS_AUTH_GAME) {
|
||||
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
|
||||
}
|
||||
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_GAME_PASSWORD()", this->client_id);
|
||||
Debug(net, 9, "client[{}] Receive_CLIENT_AUTH_RESPONSE()", this->client_id);
|
||||
|
||||
std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH);
|
||||
auto authentication_method = this->authentication_handler->GetAuthenticationMethod();
|
||||
switch (this->authentication_handler->ReceiveResponse(p)) {
|
||||
case NetworkAuthenticationServerHandler::AUTHENTICATED:
|
||||
break;
|
||||
|
||||
/* Check game password. Allow joining if we cleared the password meanwhile */
|
||||
if (!_settings_client.network.server_password.empty() &&
|
||||
_settings_client.network.server_password.compare(password) != 0) {
|
||||
/* Password is invalid */
|
||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
||||
case NetworkAuthenticationServerHandler::RETRY_NEXT_METHOD:
|
||||
return this->SendAuthRequest();
|
||||
|
||||
case NetworkAuthenticationServerHandler::NOT_AUTHENTICATED:
|
||||
default:
|
||||
return this->SendError(GetErrorForAuthenticationMethod(authentication_method));
|
||||
}
|
||||
|
||||
return this->SendNeedCompanyPassword();
|
||||
NetworkRecvStatus status = this->SendAuthCompleted();
|
||||
if (status != NETWORK_RECV_STATUS_OKAY) return status;
|
||||
|
||||
this->authentication_handler = nullptr;
|
||||
|
||||
Debug(net, 9, "client[{}] status = IDENTIFY", this->client_id);
|
||||
this->status = STATUS_IDENTIFY;
|
||||
|
||||
/* Reset 'lag' counters */
|
||||
this->last_frame = this->last_frame_server = _frame_counter;
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &p)
|
||||
|
@ -1978,9 +2018,9 @@ void NetworkServerShowStatusToConsole()
|
|||
{
|
||||
static const char * const stat_str[] = {
|
||||
"inactive",
|
||||
"authorizing (server password)",
|
||||
"identifing client",
|
||||
"checking NewGRFs",
|
||||
"authorizing (server password)",
|
||||
"authorizing (company password)",
|
||||
"authorized",
|
||||
"waiting",
|
||||
|
|
|
@ -23,10 +23,12 @@ extern NetworkClientSocketPool _networkclientsocket_pool;
|
|||
/** Class for handling the server side of the game connection. */
|
||||
class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<&_networkclientsocket_pool>, public NetworkGameSocketHandler, public TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED> {
|
||||
protected:
|
||||
std::unique_ptr<class NetworkAuthenticationServerHandler> authentication_handler; ///< The handler for the authentication.
|
||||
|
||||
NetworkRecvStatus Receive_CLIENT_JOIN(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_IDENTIFY(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_AUTH_RESPONSE(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_GETMAP(Packet &p) override;
|
||||
NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet &p) override;
|
||||
|
@ -44,16 +46,17 @@ protected:
|
|||
NetworkRecvStatus SendGameInfo();
|
||||
NetworkRecvStatus SendNewGRFCheck();
|
||||
NetworkRecvStatus SendWelcome();
|
||||
NetworkRecvStatus SendNeedGamePassword();
|
||||
NetworkRecvStatus SendAuthRequest();
|
||||
NetworkRecvStatus SendAuthCompleted();
|
||||
NetworkRecvStatus SendNeedCompanyPassword();
|
||||
|
||||
public:
|
||||
/** Status of a client */
|
||||
enum ClientStatus {
|
||||
STATUS_INACTIVE, ///< The client is not connected nor active.
|
||||
STATUS_AUTH_GAME, ///< The client is authorizing with game (server) password.
|
||||
STATUS_IDENTIFY, ///< The client is identifying itself.
|
||||
STATUS_NEWGRFS_CHECK, ///< The client is checking NewGRFs.
|
||||
STATUS_AUTH_GAME, ///< The client is authorizing with game (server) password.
|
||||
STATUS_AUTH_COMPANY, ///< The client is authorizing with company password.
|
||||
STATUS_AUTHORIZED, ///< The client is authorized.
|
||||
STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map.
|
||||
|
|
|
@ -145,6 +145,7 @@ enum NetworkErrorCode {
|
|||
NETWORK_ERROR_TIMEOUT_MAP,
|
||||
NETWORK_ERROR_TIMEOUT_JOIN,
|
||||
NETWORK_ERROR_INVALID_CLIENT_NAME,
|
||||
NETWORK_ERROR_NOT_ON_ALLOW_LIST,
|
||||
|
||||
NETWORK_ERROR_END,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue