Use password hash for network server and rcon passwords
This commit is contained in:
@@ -325,8 +325,12 @@ ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nul
|
|||||||
static uint32 last_ack_frame;
|
static uint32 last_ack_frame;
|
||||||
|
|
||||||
/** One bit of 'entropy' used to generate a salt for the company passwords. */
|
/** One bit of 'entropy' used to generate a salt for the company passwords. */
|
||||||
static uint32 _password_game_seed;
|
static uint32 _company_password_game_seed;
|
||||||
/** The other bit of 'entropy' used to generate a salt for the company passwords. */
|
/** One bit of 'entropy' used to generate a salt for the server passwords. */
|
||||||
|
static uint32 _server_password_game_seed;
|
||||||
|
/** One bit of 'entropy' used to generate a salt for the rcon passwords. */
|
||||||
|
static uint32 _rcon_password_game_seed;
|
||||||
|
/** One bit of 'entropy' used to generate a salt for the settings passwords. */
|
||||||
static char _password_server_id[NETWORK_SERVER_ID_LENGTH];
|
static char _password_server_id[NETWORK_SERVER_ID_LENGTH];
|
||||||
|
|
||||||
/** Maximum number of companies of the currently joined server. */
|
/** Maximum number of companies of the currently joined server. */
|
||||||
@@ -394,7 +398,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk()
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *password)
|
||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD);
|
Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD);
|
||||||
p->Send_string(password);
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _server_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -406,7 +410,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *p
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char *password)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char *password)
|
||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD);
|
Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD);
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -504,7 +508,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const char *pa
|
|||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD);
|
Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD);
|
||||||
|
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -541,7 +545,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit()
|
|||||||
NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const char *pass, const char *command)
|
NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const char *pass, const char *command)
|
||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_RCON);
|
Packet *p = new Packet(PACKET_CLIENT_RCON);
|
||||||
p->Send_string(pass);
|
p->Send_string(GenerateCompanyPasswordHash(pass, _password_server_id, _rcon_password_game_seed));
|
||||||
p->Send_string(command);
|
p->Send_string(command);
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
@@ -556,7 +560,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, co
|
|||||||
{
|
{
|
||||||
Packet *p = new Packet(PACKET_CLIENT_MOVE);
|
Packet *p = new Packet(PACKET_CLIENT_MOVE);
|
||||||
p->Send_uint8(company);
|
p->Send_uint8(company);
|
||||||
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed));
|
p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _company_password_game_seed));
|
||||||
my_client->SendPacket(p);
|
my_client->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -773,6 +777,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW
|
|||||||
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;
|
||||||
this->status = STATUS_AUTH_GAME;
|
this->status = STATUS_AUTH_GAME;
|
||||||
|
|
||||||
|
_server_password_game_seed = p->Recv_uint32();
|
||||||
|
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||||
|
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
const char *password = _network_join_server_password;
|
const char *password = _network_join_server_password;
|
||||||
if (!StrEmpty(password)) {
|
if (!StrEmpty(password)) {
|
||||||
return SendGamePassword(password);
|
return SendGamePassword(password);
|
||||||
@@ -788,7 +796,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA
|
|||||||
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
this->status = STATUS_AUTH_COMPANY;
|
this->status = STATUS_AUTH_COMPANY;
|
||||||
|
|
||||||
_password_game_seed = p->Recv_uint32();
|
_company_password_game_seed = p->Recv_uint32();
|
||||||
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||||
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
@@ -810,7 +818,9 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet
|
|||||||
_network_own_client_id = (ClientID)p->Recv_uint32();
|
_network_own_client_id = (ClientID)p->Recv_uint32();
|
||||||
|
|
||||||
/* Initialize the password hash salting variables, even if they were previously. */
|
/* Initialize the password hash salting variables, even if they were previously. */
|
||||||
_password_game_seed = p->Recv_uint32();
|
_company_password_game_seed = p->Recv_uint32();
|
||||||
|
_server_password_game_seed = p->Recv_uint32();
|
||||||
|
_rcon_password_game_seed = p->Recv_uint32();
|
||||||
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
p->Recv_string(_password_server_id, sizeof(_password_server_id));
|
||||||
|
|
||||||
/* Start receiving the map */
|
/* Start receiving the map */
|
||||||
|
@@ -216,6 +216,8 @@ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : Netwo
|
|||||||
this->status = STATUS_INACTIVE;
|
this->status = STATUS_INACTIVE;
|
||||||
this->client_id = _network_client_id++;
|
this->client_id = _network_client_id++;
|
||||||
this->receive_limit = _settings_client.network.bytes_per_frame_burst;
|
this->receive_limit = _settings_client.network.bytes_per_frame_burst;
|
||||||
|
this->server_hash_bits = InteractiveRandom();
|
||||||
|
this->rcon_hash_bits = InteractiveRandom();
|
||||||
|
|
||||||
/* The Socket and Info pools need to be the same in size. After all,
|
/* The Socket and Info pools need to be the same in size. After all,
|
||||||
* each Socket will be associated with at most one Info object. As
|
* each Socket will be associated with at most one Info object. As
|
||||||
@@ -492,6 +494,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
|
|||||||
this->last_frame = this->last_frame_server = _frame_counter;
|
this->last_frame = this->last_frame_server = _frame_counter;
|
||||||
|
|
||||||
Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
|
Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD);
|
||||||
|
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits);
|
||||||
|
p->Send_string(_settings_client.network.network_id);
|
||||||
this->SendPacket(p);
|
this->SendPacket(p);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
@@ -531,6 +535,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
|
|||||||
p = new Packet(PACKET_SERVER_WELCOME);
|
p = new Packet(PACKET_SERVER_WELCOME);
|
||||||
p->Send_uint32(this->client_id);
|
p->Send_uint32(this->client_id);
|
||||||
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
p->Send_uint32(_settings_game.game_creation.generation_seed);
|
||||||
|
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->server_hash_bits);
|
||||||
|
p->Send_uint32(_settings_game.game_creation.generation_seed ^ this->rcon_hash_bits);
|
||||||
p->Send_string(_settings_client.network.network_id);
|
p->Send_string(_settings_client.network.network_id);
|
||||||
this->SendPacket(p);
|
this->SendPacket(p);
|
||||||
|
|
||||||
@@ -972,7 +978,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(P
|
|||||||
|
|
||||||
/* Check game password. Allow joining if we cleared the password meanwhile */
|
/* Check game password. Allow joining if we cleared the password meanwhile */
|
||||||
if (!StrEmpty(_settings_client.network.server_password) &&
|
if (!StrEmpty(_settings_client.network.server_password) &&
|
||||||
strcmp(password, _settings_client.network.server_password) != 0) {
|
strcmp(password, GenerateCompanyPasswordHash(_settings_client.network.server_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->server_hash_bits)) != 0) {
|
||||||
/* Password is invalid */
|
/* Password is invalid */
|
||||||
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
|
||||||
}
|
}
|
||||||
@@ -1481,7 +1487,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p)
|
|||||||
p->Recv_string(pass, sizeof(pass));
|
p->Recv_string(pass, sizeof(pass));
|
||||||
p->Recv_string(command, sizeof(command));
|
p->Recv_string(command, sizeof(command));
|
||||||
|
|
||||||
if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
|
if (strcmp(pass, GenerateCompanyPasswordHash(_settings_client.network.rcon_password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed ^ this->rcon_hash_bits)) != 0) {
|
||||||
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id);
|
||||||
return NETWORK_RECV_STATUS_OKAY;
|
return NETWORK_RECV_STATUS_OKAY;
|
||||||
}
|
}
|
||||||
|
@@ -72,6 +72,8 @@ public:
|
|||||||
ClientStatus status; ///< Status of this client
|
ClientStatus status; ///< Status of this client
|
||||||
CommandQueue outgoing_queue; ///< The command-queue awaiting delivery
|
CommandQueue outgoing_queue; ///< The command-queue awaiting delivery
|
||||||
int receive_limit; ///< Amount of bytes that we can receive at this moment
|
int receive_limit; ///< Amount of bytes that we can receive at this moment
|
||||||
|
uint32 server_hash_bits; ///< Server password hash entropy bits
|
||||||
|
uint32 rcon_hash_bits; ///< Rcon password hash entropy bits
|
||||||
|
|
||||||
struct PacketWriter *savegame; ///< Writer used to write the savegame.
|
struct PacketWriter *savegame; ///< Writer used to write the savegame.
|
||||||
NetworkAddress client_address; ///< IP-address of the client (so he can be banned)
|
NetworkAddress client_address; ///< IP-address of the client (so he can be banned)
|
||||||
|
Reference in New Issue
Block a user