From 03bad9e6f56e246c37624dd142de2c08479dbd9f Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 26 May 2021 12:32:03 +0200 Subject: [PATCH] Using proper permission inheritance --- server/src/PermissionCalculator.cpp | 72 +++++++++++----------- server/src/PermissionCalculator.h | 4 +- server/src/TS3ServerClientManager.cpp | 1 - server/src/client/ConnectedClient.cpp | 20 +++--- server/src/client/command_handler/misc.cpp | 3 + 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/server/src/PermissionCalculator.cpp b/server/src/PermissionCalculator.cpp index b7b958d..339c543 100644 --- a/server/src/PermissionCalculator.cpp +++ b/server/src/PermissionCalculator.cpp @@ -24,35 +24,23 @@ ClientPermissionCalculator::ClientPermissionCalculator(DataClient *client, Chann std::shared_ptr channel{}; try { std::shared_lock channel_lock{server->get_channel_tree_lock()}; - channel = server->getChannelTree()->findChannel(channel_id); + this->channel_ = server->getChannelTree()->findChannel(channel_id); } catch (std::system_error& e) { if(e.code() != std::errc::resource_deadlock_would_occur) { throw; } /* tree already write locked, no need to lock it again */ - channel = server->getChannelTree()->findChannel(channel_id); - } - - if(channel) { - this->channel_permissions = channel->permissions(); + this->channel_ = server->getChannelTree()->findChannel(channel_id); } } - this->channel_id_ = channel_id; } ClientPermissionCalculator::ClientPermissionCalculator(DataClient *client, const std::shared_ptr &channel) { /* Note: Order matters! */ this->initialize_client(client); this->initialize_default_groups(client->getServer()); - - if(channel) { - this->channel_id_ = channel->channelId(); - this->channel_permissions = channel->permissions(); - } else { - this->channel_id_ = 0; - this->channel_permissions = nullptr; - } + this->channel_ = channel; } ClientPermissionCalculator::ClientPermissionCalculator( @@ -63,26 +51,21 @@ ClientPermissionCalculator::ClientPermissionCalculator( this->client_database_id = client_database_id; this->client_type = client_type; - this->channel_id_ = channel_id; if(server) { this->virtual_server_id = server->getServerId(); this->group_manager_ = server->group_manager(); - std::shared_ptr channel{}; try { std::shared_lock channel_lock{server->get_channel_tree_lock()}; - channel = server->getChannelTree()->findChannel(channel_id); + this->channel_ = server->getChannelTree()->findChannel(channel_id); } catch (std::system_error& e) { if(e.code() != std::errc::resource_deadlock_would_occur) { throw; } /* tree already write locked, no need to lock it again */ - channel = server->getChannelTree()->findChannel(channel_id); - } - if(channel) { - this->channel_permissions = channel->permissions(); + this->channel_ = server->getChannelTree()->findChannel(channel_id); } } else { this->virtual_server_id = 0; @@ -216,8 +199,8 @@ std::vector> ClientPermissionC server_group_data_initialized = false; /* reset all group data */ auto client_permission_flags = client_permissions->permission_flags(permission); /* lets try to resolve the channel specific permission */ - if(this->channel_id_ > 0 && client_permission_flags.channel_specific) { - auto data = client_permissions->channel_permission(permission, this->channel_id_); + if(this->channel_ && client_permission_flags.channel_specific) { + auto data = client_permissions->channel_permission(permission, this->channel_->channelId()); if(calculate_granted ? data.flags.grant_set : data.flags.value_set) { result.push_back({permission, {calculate_granted ? data.values.grant : data.values.value, true}}); logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Client channel permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, data.values.value); @@ -226,7 +209,7 @@ std::vector> ClientPermissionC } - bool skip_channel_permissions = this->channel_id_ == 0 || this->has_global_skip_permission(); + bool skip_channel_permissions = !this->channel_ || this->has_global_skip_permission(); if(!skip_channel_permissions) { /* We dont have a global skip flag. Lets see if the target permission has skip enabled */ if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) { @@ -262,8 +245,9 @@ std::vector> ClientPermissionC } /* lookup the channel permissions. Whyever? */ - if(this->channel_permissions) { - auto data = calculate_granted ? this->channel_permissions->permission_granted_flagged(permission) : this->channel_permissions->permission_value_flagged(permission); + if(this->channel_) { + auto channel_permissions = this->channel_->permissions(); + auto data = calculate_granted ? channel_permissions->permission_granted_flagged(permission) : channel_permissions->permission_value_flagged(permission); if(data.has_value) { result.push_back({permission, {data.value, true}}); logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Channel permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, data.value); @@ -341,22 +325,38 @@ const std::shared_ptr& ClientPermissionCalculator::assigne } this->assigned_channel_group_.emplace(); - if(this->channel_id_ == 0) { + if(!this->channel_) { return *this->assigned_channel_group_; } - auto channel_group_assignment = this->group_manager_->assignments().exact_channel_group_of_client( - groups::GroupAssignmentCalculateMode::GLOBAL, this->client_database_id, this->channel_id_); - if(!channel_group_assignment.has_value()) { - return *this->assigned_channel_group_; + std::shared_ptr inherited_channel{this->channel_}; + auto channel_group_assignment = this->group_manager_->assignments().calculate_channel_group_of_client( + groups::GroupAssignmentCalculateMode::GLOBAL, + this->client_database_id, + inherited_channel + ); + + if(channel_group_assignment.has_value()) { + assert(inherited_channel); + auto channel_group = this->group_manager_->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, *channel_group_assignment); + if(channel_group) { + this->assigned_channel_group_.emplace(std::move(channel_group)); + logTrace(this->virtual_server_id, "[Permission] Using calculated channel group with id {} (Channel id: {}, Inherited channel id: {}).", + *channel_group_assignment, this->channel_->channelId(), inherited_channel->channelId()); + } else { + logTrace(this->virtual_server_id, "[Permission] Missing calculated channel group with id {} (Channel id: {}, Inherited channel id: {}). Using default channel group.", + *channel_group_assignment, this->channel_->channelId(), inherited_channel->channelId()); + } + } else { + logTrace(this->virtual_server_id, "[Permission] Using default channel group."); } - auto channel_group = this->group_manager_->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, channel_group_assignment->group_id); - if(!channel_group) { - channel_group = this->default_channel_group(); + if(!this->assigned_channel_group_.has_value()) { + assigned_channel_group_.emplace( + this->default_channel_group() + ); } - *this->assigned_channel_group_ = channel_group; return *this->assigned_channel_group_; } diff --git a/server/src/PermissionCalculator.h b/server/src/PermissionCalculator.h index 08baf89..038c288 100644 --- a/server/src/PermissionCalculator.h +++ b/server/src/PermissionCalculator.h @@ -89,9 +89,9 @@ namespace ts::server { ServerId virtual_server_id; ClientDbId client_database_id; ClientType client_type; - ChannelId channel_id_; + std::shared_ptr channel_; + std::shared_ptr group_manager_{}; - std::shared_ptr channel_permissions{}; std::function()> default_channel_group{[]{ return nullptr; }}; std::function()> default_server_group{[]{ return nullptr; }}; diff --git a/server/src/TS3ServerClientManager.cpp b/server/src/TS3ServerClientManager.cpp index e0ab9e3..b9ba7a2 100644 --- a/server/src/TS3ServerClientManager.cpp +++ b/server/src/TS3ServerClientManager.cpp @@ -551,7 +551,6 @@ void VirtualServer::client_move( } } TIMING_STEP(timings, "notify view"); - target_client->currentChannel = target_channel; /* third step: update stuff for the client (remember: the client cant execute anything at the moment!) */ diff --git a/server/src/client/ConnectedClient.cpp b/server/src/client/ConnectedClient.cpp index 34d4834..e29384b 100644 --- a/server/src/client/ConnectedClient.cpp +++ b/server/src/client/ConnectedClient.cpp @@ -1169,32 +1169,36 @@ permission::PermissionType ConnectedClient::calculate_and_get_join_state(const s return ventry->join_permission_error; } - auto channel_id = channel->channelId(); + ClientPermissionCalculator target_permissions{this, channel}; + switch(channel->channelType()) { case ChannelType::permanent: - if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_permanent, channel_id))) { + if(!target_permissions.permission_granted(permission::b_channel_join_permanent, 1)) { RESULT(permission::b_channel_join_permanent); } break; case ChannelType::semipermanent: - if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_semi_permanent, channel_id))) { + if(!target_permissions.permission_granted(permission::b_channel_join_semi_permanent, 1)) { RESULT(permission::b_channel_join_semi_permanent); } break; case ChannelType::temporary: - if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_temporary, channel_id))) { + if(!target_permissions.permission_granted(permission::b_channel_join_temporary, 1)) { RESULT(permission::b_channel_join_temporary); } break; } - if(!channel->permission_granted(permission::i_channel_needed_join_power, this->calculate_permission(permission::i_channel_join_power, channel_id), false)) { - if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_ignore_join_power, channel_id))) { + + auto required_join_power = channel->permissions()->permission_value_flagged(permission::i_channel_needed_join_power); + required_join_power.clear_flag_on_zero(); + if(!target_permissions.permission_granted(permission::i_channel_join_power, required_join_power)) { + if(!target_permissions.permission_granted(permission::b_channel_ignore_join_power, 1)) { RESULT(permission::i_channel_join_power); } } - if(permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_is_sticky, this->currentChannel ? this->currentChannel->channelId() : 0))) { - if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ignore_sticky, channel_id))) { + if(permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_is_sticky, this->getChannelId()))) { + if(!target_permissions.permission_granted(permission::b_client_ignore_sticky, 1)) { RESULT(permission::b_client_is_sticky); } } diff --git a/server/src/client/command_handler/misc.cpp b/server/src/client/command_handler/misc.cpp index dfeed2c..7e6c13d 100644 --- a/server/src/client/command_handler/misc.cpp +++ b/server/src/client/command_handler/misc.cpp @@ -526,6 +526,9 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd) for (const auto &targetClient : this->server->findClientsByCldbId(target_cldbid)) { connected_client = targetClient; + /* Permissions might changed because of group inheritance */ + targetClient->join_state_id++; + bool channel_group_changed, server_group_changed; targetClient->update_displayed_client_groups(server_group_changed, channel_group_changed);