wesnothd: avoid a race condition when logging on

Ensure that there is no coroutine yield between confirmation of login
and update of player_connections_. Otherwise another login under same
name could succeed if it happened before handle_player() which resulted
in an assert later.
This commit is contained in:
Sergey Popov 2024-08-09 12:50:08 +03:00 committed by GitHub
parent 8863cd1bcd
commit c10c47ebb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 19 deletions

View file

@ -752,15 +752,8 @@ void server::login_client(boost::asio::yield_context yield, SocketPtr socket)
async_send_error(socket, "You must login first.", MP_MUST_LOGIN);
}
simple_wml::document join_lobby_response;
join_lobby_response.root().add_child("join_lobby").set_attr("is_moderator", is_moderator ? "yes" : "no");
join_lobby_response.root().child("join_lobby")->set_attr_dup("profile_url_prefix", "https://r.wesnoth.org/u");
coro_send_doc(socket, join_lobby_response, yield);
simple_wml::node& player_cfg = games_and_users_list_.root().add_child("user");
boost::asio::spawn(io_service_,
[this, socket, new_player = wesnothd::player{
wesnothd::player player_data {
username,
player_cfg,
user_handler_ ? user_handler_->get_forum_id(username) : 0,
@ -771,7 +764,19 @@ void server::login_client(boost::asio::yield_context yield, SocketPtr socket)
default_max_messages_,
default_time_period_,
is_moderator
}](boost::asio::yield_context yield) { handle_player(yield, socket, new_player); }
};
bool inserted;
player_iterator new_player;
std::tie(new_player, inserted) = player_connections_.insert(player_connections::value_type(socket, player_data));
assert(inserted && "unexpected duplicate username");
simple_wml::document join_lobby_response;
join_lobby_response.root().add_child("join_lobby").set_attr("is_moderator", is_moderator ? "yes" : "no");
join_lobby_response.root().child("join_lobby")->set_attr_dup("profile_url_prefix", "https://r.wesnoth.org/u");
coro_send_doc(socket, join_lobby_response, yield);
boost::asio::spawn(io_service_,
[this, socket, new_player](boost::asio::yield_context yield) { handle_player(yield, socket, new_player); }
);
LOG_SERVER << log_address(socket) << "\t" << username << "\thas logged on"
@ -1050,16 +1055,11 @@ template<class SocketPtr> void server::send_password_request(SocketPtr socket,
async_send_doc_queued(socket, doc);
}
template<class SocketPtr> void server::handle_player(boost::asio::yield_context yield, SocketPtr socket, const player& player_data)
template<class SocketPtr> void server::handle_player(boost::asio::yield_context yield, SocketPtr socket, player_iterator player)
{
if(lan_server_)
abort_lan_server_timer();
bool inserted;
player_iterator player;
std::tie(player, inserted) = player_connections_.insert(player_connections::value_type(socket, player_data));
assert(inserted);
BOOST_SCOPE_EXIT_ALL(this, &player) {
if(!destructed) {
remove_player(player);
@ -1073,10 +1073,10 @@ template<class SocketPtr> void server::handle_player(boost::asio::yield_context
}
send_server_message(player, information_, "server_info");
send_server_message(player, announcements_+tournaments_, "announcements");
if(version_info(player_data.version()) < secure_version ){
send_server_message(player, "You are using version " + player_data.version() + " which has known security issues that can be used to compromise your computer. We strongly recommend updating to a Wesnoth version " + secure_version.str() + " or newer!", "alert");
if(version_info(player->info().version()) < secure_version ){
send_server_message(player, "You are using version " + player->info().version() + " which has known security issues that can be used to compromise your computer. We strongly recommend updating to a Wesnoth version " + secure_version.str() + " or newer!", "alert");
}
if(version_info(player_data.version()) < version_info(recommended_version_)) {
if(version_info(player->info().version()) < version_info(recommended_version_)) {
send_server_message(player, "A newer Wesnoth version, " + recommended_version_ + ", is out!", "alert");
}

View file

@ -54,7 +54,7 @@ private:
template<class SocketPtr> void send_password_request(SocketPtr socket, const std::string& msg, const char* error_code = "", bool force_confirmation = false);
bool accepting_connections() const { return !graceful_restart; }
template<class SocketPtr> void handle_player(boost::asio::yield_context yield, SocketPtr socket, const player& player);
template<class SocketPtr> void handle_player(boost::asio::yield_context yield, SocketPtr socket, player_iterator player);
void handle_player_in_lobby(player_iterator player, simple_wml::document& doc);
void handle_player_in_game(player_iterator player, simple_wml::document& doc);
void handle_whisper(player_iterator player, simple_wml::node& whisper);