From 71fc9075840e9263433a4dbbb0f1c38a6f8eed27 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Sat, 23 Mar 2024 18:55:43 +0100 Subject: [PATCH] Change: remove company passwords over client allow lists --- src/network/network.cpp | 12 ++------ src/network/network_client.cpp | 4 +-- src/network/network_func.h | 2 -- src/network/network_gui.cpp | 20 ++++--------- src/network/network_internal.h | 2 -- src/network/network_server.cpp | 52 ++++++++-------------------------- src/network/network_type.h | 5 ---- 7 files changed, 21 insertions(+), 76 deletions(-) diff --git a/src/network/network.cpp b/src/network/network.cpp index 710c2091c4..04e201ded2 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -67,7 +67,6 @@ bool _network_server; ///< network-server is active bool _network_available; ///< is network mode available? bool _network_dedicated; ///< are we a dedicated server? bool _is_network_server; ///< Does this client wants to be a network-server? -NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies. ClientID _network_own_client_id; ///< Our client identifier. ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client. uint8_t _network_reconnect; ///< Reconnect timeout @@ -85,7 +84,6 @@ uint32_t _sync_seed_2; ///< Second part of the seed. #endif uint32_t _sync_frame; ///< The frame to perform the sync check. bool _network_first_time; ///< Whether we have finished joining or not. -CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies. static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH); @@ -287,9 +285,9 @@ std::string GenerateCompanyPasswordHash(const std::string &password, const std:: * @param company_id id of the company we want to check the 'passworded' flag for. * @return true if the company requires a password. */ -bool NetworkCompanyIsPassworded(CompanyID company_id) +bool NetworkCompanyIsPassworded([[maybe_unused]] CompanyID company_id) { - return HasBit(_network_company_passworded, company_id); + return false; } /* This puts a text-message to the console, or in the future, the chat-box, @@ -687,10 +685,6 @@ void NetworkClose(bool close_admins) NetworkFreeLocalCommandQueue(); - delete[] _network_company_states; - _network_company_states = nullptr; - _network_company_passworded = 0; - InitializeNetworkPools(close_admins); } @@ -985,7 +979,6 @@ bool NetworkServerStart() Debug(net, 5, "Starting listeners for incoming server queries"); NetworkUDPServerListen(); - _network_company_states = new NetworkCompanyState[MAX_COMPANIES]; _network_server = true; _networking = true; _frame_counter = 0; @@ -995,7 +988,6 @@ bool NetworkServerStart() _network_own_client_id = CLIENT_ID_SERVER; _network_clients_connected = 0; - _network_company_passworded = 0; NetworkInitGameInfo(); diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 1e6dda3b57..a6e6f3277b 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -1261,12 +1261,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(P return NETWORK_RECV_STATUS_OKAY; } -NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet &p) +NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet &) { if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; - static_assert(sizeof(_network_company_passworded) <= sizeof(uint16_t)); - _network_company_passworded = p.Recv_uint16(); SetWindowClassesDirty(WC_COMPANY); Debug(net, 9, "Client::Receive_SERVER_COMPANY_UPDATE()"); diff --git a/src/network/network_func.h b/src/network/network_func.h index 35539fa9f6..e4a43be710 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -24,8 +24,6 @@ #include "../company_type.h" #include "../string_type.h" -extern NetworkCompanyState *_network_company_states; - extern ClientID _network_own_client_id; extern ClientID _redirect_console_to_client; extern uint8_t _network_reconnect; diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 12333ef4d7..c9c6333321 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1423,7 +1423,6 @@ using ClientButton = Button; struct NetworkClientListWindow : Window { private: ClientListWidgets query_widget; ///< During a query this tracks what widget caused the query. - CompanyID join_company; ///< During query for company password, this stores what company we wanted to join. ClientID dd_client_id; ///< During admin dropdown, track which client this was for. CompanyID dd_company_id; ///< During admin dropdown, track which company this was for. @@ -1459,10 +1458,6 @@ private: if (_network_server) { NetworkServerDoMove(CLIENT_ID_SERVER, company_id); MarkWholeScreenDirty(); - } else if (NetworkCompanyIsPassworded(company_id)) { - w->query_widget = WID_CL_COMPANY_JOIN; - w->join_company = company_id; - ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_PASSWORD); } else { NetworkClientRequestMove(company_id); } @@ -1546,14 +1541,15 @@ private: * Part of RebuildList() to create the information for a single company. * @param company_id The company to build the list for. * @param client_playas The company the client is joined as. + * @param can_join_company Whether this company can be joined by us. */ - void RebuildListCompany(CompanyID company_id, CompanyID client_playas) + void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company) { ButtonCommon *chat_button = new CompanyButton(SPR_CHAT, company_id == COMPANY_SPECTATOR ? STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP : STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyChat); if (_network_server) this->buttons[line_count].push_back(std::make_unique(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR)); this->buttons[line_count].emplace_back(chat_button); - if (client_playas != company_id) this->buttons[line_count].push_back(std::make_unique(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai)); + if (can_join_company) this->buttons[line_count].push_back(std::make_unique(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai)); this->line_count += 1; @@ -1599,18 +1595,18 @@ private: } if (client_playas != COMPANY_SPECTATOR) { - this->RebuildListCompany(client_playas, client_playas); + this->RebuildListCompany(client_playas, client_playas, false); } /* Companies */ for (const Company *c : Company::Iterate()) { if (c->index == client_playas) continue; - this->RebuildListCompany(c->index, client_playas); + this->RebuildListCompany(c->index, client_playas, (own_ci != nullptr && c->allow_list.Contains(own_ci->public_key)) || _network_server); } /* Spectators */ - this->RebuildListCompany(COMPANY_SPECTATOR, client_playas); + this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR); this->vscroll->SetCount(this->line_count); } @@ -1914,10 +1910,6 @@ public: this->InvalidateData(); break; } - - case WID_CL_COMPANY_JOIN: - NetworkClientRequestMove(this->join_company, str); - break; } } diff --git a/src/network/network_internal.h b/src/network/network_internal.h index 35adc68983..1c2fe23ef2 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -80,8 +80,6 @@ extern std::string _network_server_name; extern uint8_t _network_reconnect; -extern CompanyMask _network_company_passworded; - void NetworkQueryServer(const std::string &connection_string); void GetBindAddresses(NetworkAddressList *addresses, uint16_t port); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 3e7bafb0c3..b0ff3cf164 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -485,7 +485,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword() this->status = STATUS_AUTH_COMPANY; NetworkClientInfo *ci = this->GetInfo(); - if (!Company::IsValidID(ci->client_playas) || _network_company_states[ci->client_playas].password.empty()) { + if (!Company::IsValidID(ci->client_playas)) { return this->SendWelcome(); } @@ -847,8 +847,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate() auto p = std::make_unique(this, PACKET_SERVER_COMPANY_UPDATE); - static_assert(sizeof(_network_company_passworded) <= sizeof(uint16_t)); - p->Send_uint16(_network_company_passworded); + p->Send_uint16(0); this->SendPacket(std::move(p)); return NETWORK_RECV_STATUS_OKAY; } @@ -939,6 +938,11 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_IDENTIFY(Packet if (!Company::IsValidHumanID(playas)) { return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH); } + + if (!Company::Get(playas)->allow_list.Contains(this->peer_public_key)) { + /* When we're not authorized, just bump us to a spectator. */ + playas = COMPANY_SPECTATOR; + } break; } @@ -1021,7 +1025,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_AUTH_RESPONSE(P return NETWORK_RECV_STATUS_OKAY; } -NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &p) +NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet &) { if (this->status != STATUS_AUTH_COMPANY) { return this->SendError(NETWORK_ERROR_NOT_EXPECTED); @@ -1029,18 +1033,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWOR Debug(net, 9, "client[{}] Receive_CLIENT_COMPANY_PASSWORD()", this->client_id); - std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH); - - /* Check company password. Allow joining if we cleared the password meanwhile. - * Also, check the company is still valid - client could be moved to spectators - * in the middle of the authorization process */ - CompanyID playas = this->GetInfo()->client_playas; - if (Company::IsValidID(playas) && !_network_company_states[playas].password.empty() && - _network_company_states[playas].password.compare(password) != 0) { - /* Password is invalid */ - return this->SendError(NETWORK_ERROR_WRONG_PASSWORD); - } - return this->SendWelcome(); } @@ -1559,16 +1551,9 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet &p) /* Check if the company is valid, we don't allow moving to AI companies */ if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY; - /* Check if we require a password for this company */ - if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key) && !_network_company_states[company_id].password.empty()) { - /* we need a password from the client - should be in this packet */ - std::string password = p.Recv_string(NETWORK_PASSWORD_LENGTH); - - /* Incorrect password sent, return! */ - if (_network_company_states[company_id].password.compare(password) != 0) { - Debug(net, 2, "Wrong password from client-id #{} for company #{}", this->client_id, company_id + 1); - return NETWORK_RECV_STATUS_OKAY; - } + if (company_id != COMPANY_SPECTATOR && !Company::Get(company_id)->allow_list.Contains(this->peer_public_key)) { + Debug(net, 2, "Wrong public key from client-id #{} for company #{}", this->client_id, company_id + 1); + return NETWORK_RECV_STATUS_OKAY; } /* if we get here we can move the client */ @@ -1758,17 +1743,8 @@ bool NetworkServerChangeClientName(ClientID client_id, const std::string &new_na * @param password The new password. * @param already_hashed Is the given password already hashed? */ -void NetworkServerSetCompanyPassword(CompanyID company_id, const std::string &password, bool already_hashed) +void NetworkServerSetCompanyPassword([[maybe_unused]] CompanyID company_id, [[maybe_unused]] const std::string &password, [[maybe_unused]] bool already_hashed) { - if (!Company::IsValidHumanID(company_id)) return; - - if (already_hashed) { - _network_company_states[company_id].password = password; - } else { - _network_company_states[company_id].password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed); - } - - NetworkServerUpdateCompanyPassworded(company_id, !_network_company_states[company_id].password.empty()); } /** @@ -2088,7 +2064,6 @@ void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded) { if (NetworkCompanyIsPassworded(company_id) == passworded) return; - SB(_network_company_passworded, company_id, 1, !!passworded); SetWindowClassesDirty(WC_COMPANY); for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) { @@ -2278,9 +2253,6 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci) if (!_network_server) return; - _network_company_states[c->index].password.clear(); - NetworkServerUpdateCompanyPassworded(c->index, false); - if (ci != nullptr) { /* ci is nullptr when replaying, or for AIs. In neither case there is a client. */ ci->client_playas = c->index; diff --git a/src/network/network_type.h b/src/network/network_type.h index 4f8617ff37..0ab7d51558 100644 --- a/src/network/network_type.h +++ b/src/network/network_type.h @@ -70,11 +70,6 @@ struct NetworkCompanyStats { bool ai; ///< Is this company an AI }; -/** Some state information of a company, especially for servers */ -struct NetworkCompanyState { - std::string password; ///< The password for the company -}; - struct NetworkClientInfo; /** The type of password we're asking for. */