// // Created by wolverindev on 26.01.20. // #include #include #include #include #include #include #include "../../build.h" #include "../ConnectedClient.h" #include "../InternalClient.h" #include "../../server/file/FileServer.h" #include "../../server/VoiceServer.h" #include "../voice/VoiceClient.h" #include "PermissionManager.h" #include "../../InstanceHandler.h" #include "../../server/QueryServer.h" #include "../file/FileClient.h" #include "../music/MusicClient.h" #include "../query/QueryClient.h" #include "../../weblist/WebListManager.h" #include "../../manager/ConversationManager.h" #include "../../manager/PermissionNameMapper.h" #include #include #include #include "helpers.h" #include #include #include #include #include #include #include #include #include #include #include namespace fs = std::experimental::filesystem; using namespace std::chrono; using namespace std; using namespace ts; using namespace ts::server; using namespace ts::token; #define QUERY_PASSWORD_LENGTH 12 command_result ConnectedClient::handleCommandServerGetVariables(Command &cmd) { CMD_REQ_SERVER; this->notifyServerUpdated(_this.lock()); return command_result{error::ok}; } #define SERVEREDIT_CHK_PROP_CACHED(name, perm, type)\ else if(key == name) { \ ACTION_REQUIRES_GLOBAL_PERMISSION(perm, 1); \ if(toApplay.count(key) == 0) toApplay[key] = cmd[key].as(); \ if(!cmd[0][key].castable()) return command_result{error::parameter_invalid}; #define SERVEREDIT_CHK_PROP2(name, perm, type_a, type_b)\ else if(key == name) { \ ACTION_REQUIRES_GLOBAL_PERMISSION(perm, 1); \ if(toApplay.count(key) == 0) toApplay[key] = cmd[key].as(); \ if(!cmd[0][key].castable() && !!cmd[0][key].castable()) return command_result{error::parameter_invalid}; command_result ConnectedClient::handleCommandServerEdit(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); if (cmd[0].has("sid") && this->getServerId() != cmd["sid"].as()) return command_result{error::server_invalid_id}; auto target_server = this->server; if(cmd[0].has("sid")) { target_server = serverInstance->getVoiceServerManager()->findServerById(cmd["sid"]); if(!target_server && cmd["sid"].as() != 0) return command_result{error::server_invalid_id}; } auto cache = make_shared(); map toApplay; for (auto &key : cmd[0].keys()) { if (key == "sid") continue; SERVEREDIT_CHK_PROP_CACHED("virtualserver_name", permission::b_virtualserver_modify_name, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_name_phonetic", permission::b_virtualserver_modify_name, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_maxclients", permission::b_virtualserver_modify_maxclients, size_t) if (cmd["virtualserver_maxclients"].as() > 1024) return command_result{error::accounting_slot_limit_reached, "Do you really need more that 1024 slots?"}; } SERVEREDIT_CHK_PROP_CACHED("virtualserver_reserved_slots", permission::b_virtualserver_modify_reserved_slots, size_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_max_channels", permission::b_virtualserver_modify_maxchannels, size_t) if(cmd["virtualserver_max_channels"].as() > 8192) return command_result{error::channel_protocol_limit_reached}; } SERVEREDIT_CHK_PROP_CACHED("virtualserver_icon_id", permission::b_virtualserver_modify_icon_id, int64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_channel_temp_delete_delay_default", permission::b_virtualserver_modify_channel_temp_delete_delay_default, ChannelId) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_codec_encryption_mode", permission::b_virtualserver_modify_codec_encryption_mode, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_server_group", permission::b_virtualserver_modify_default_servergroup, GroupId) if(target_server) { auto group = target_server->groups->findGroup(cmd["virtualserver_default_server_group"].as()); if (!group || group->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_channel_group", permission::b_virtualserver_modify_default_channelgroup, GroupId) if(target_server) { auto group = target_server->groups->findGroup(cmd["virtualserver_default_channel_group"].as()); if (!group || group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid}; } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_channel_admin_group", permission::b_virtualserver_modify_default_channeladmingroup, GroupId) if(target_server) { auto group = target_server->groups->findGroup(cmd["virtualserver_default_channel_admin_group"].as()); if (!group || group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid}; } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_music_group", permission::b_virtualserver_modify_default_musicgroup, GroupId) if(target_server) { auto group = target_server->groups->findGroup(cmd["virtualserver_default_music_group"].as()); if (!group || group->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_priority_speaker_dimm_modificator", permission::b_virtualserver_modify_priority_speaker_dimm_modificator, float) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_port", permission::b_virtualserver_modify_port, uint16_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_host", permission::b_virtualserver_modify_host, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_web_host", permission::b_virtualserver_modify_port, uint16_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_web_port", permission::b_virtualserver_modify_host, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostbanner_url", permission::b_virtualserver_modify_hostbanner, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostbanner_gfx_url", permission::b_virtualserver_modify_hostbanner, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostbanner_gfx_interval", permission::b_virtualserver_modify_hostbanner, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostbanner_mode", permission::b_virtualserver_modify_hostbanner, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostbutton_tooltip", permission::b_virtualserver_modify_hostbutton, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostbutton_url", permission::b_virtualserver_modify_hostbutton, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostbutton_gfx_url", permission::b_virtualserver_modify_hostbutton, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostmessage", permission::b_virtualserver_modify_hostmessage, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_hostmessage_mode", permission::b_virtualserver_modify_hostmessage, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_welcomemessage", permission::b_virtualserver_modify_welcomemessage, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_weblist_enabled", permission::b_virtualserver_modify_weblist, bool) if (target_server && target_server->running()) { if (cmd["virtualserver_weblist_enabled"].as()) serverInstance->getWebList()->enable_report(target_server); else serverInstance->getWebList()->disable_report(target_server); debugMessage(target_server->getServerId(), "Changed weblist state to -> {}", cmd["virtualserver_weblist_enabled"].as() ? "activated" : "disabled"); } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_needed_identity_security_level", permission::b_virtualserver_modify_needed_identity_security_level, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_antiflood_points_tick_reduce", permission::b_virtualserver_modify_antiflood, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_antiflood_points_needed_command_block", permission::b_virtualserver_modify_antiflood, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_antiflood_points_needed_ip_block", permission::b_virtualserver_modify_antiflood, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_complain_autoban_count", permission::b_virtualserver_modify_complain, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_complain_autoban_time", permission::b_virtualserver_modify_complain, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_complain_remove_time", permission::b_virtualserver_modify_complain, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_autostart", permission::b_virtualserver_modify_autostart, bool) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_min_clients_in_channel_before_forced_silence", permission::b_virtualserver_modify_channel_forced_silence, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_log_client", permission::b_virtualserver_modify_log_settings, bool) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_log_query", permission::b_virtualserver_modify_log_settings, bool) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_log_channel", permission::b_virtualserver_modify_log_settings, bool) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_log_permissions", permission::b_virtualserver_modify_log_settings, bool) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_log_server", permission::b_virtualserver_modify_log_settings, bool) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_log_filetransfer", permission::b_virtualserver_modify_log_settings, bool) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_min_client_version", permission::b_virtualserver_modify_min_client_version, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_min_android_version", permission::b_virtualserver_modify_min_client_version, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_min_ios_version", permission::b_virtualserver_modify_min_client_version, uint64_t) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_music_bot_limit", permission::b_virtualserver_modify_music_bot_limit, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_flag_password", permission::b_virtualserver_modify_password, bool) if (cmd["virtualserver_flag_password"].as() && !cmd[0].has("virtualserver_password")) return command_result{error::parameter_invalid}; } SERVEREDIT_CHK_PROP_CACHED("virtualserver_password", permission::b_virtualserver_modify_password, string) if(cmd["virtualserver_password"].string().empty()) { toApplay["virtualserver_flag_password"] = "0"; } else { toApplay["virtualserver_flag_password"] = "1"; if(this->getType() == CLIENT_QUERY) toApplay["virtualserver_password"] = base64::encode(digest::sha1(cmd["virtualserver_password"].string())); } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_client_description", permission::b_virtualserver_modify_default_messages, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_channel_description", permission::b_virtualserver_modify_default_messages, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_channel_topic", permission::b_virtualserver_modify_default_messages, string) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_country_code", permission::b_virtualserver_modify_country_code, string) } SERVEREDIT_CHK_PROP2("virtualserver_max_download_total_bandwidth", permission::b_virtualserver_modify_ft_settings, uint64_t, int64_t) if(cmd["virtualserver_max_download_total_bandwidth"].string().find('-') == string::npos) toApplay["virtualserver_max_download_total_bandwidth"] = to_string((int64_t) cmd["virtualserver_max_download_total_bandwidth"].as()); else toApplay["virtualserver_max_download_total_bandwidth"] = to_string(cmd["virtualserver_max_download_total_bandwidth"].as()); } SERVEREDIT_CHK_PROP2("virtualserver_max_upload_total_bandwidth", permission::b_virtualserver_modify_ft_settings, uint64_t, int64_t) if(cmd["virtualserver_max_upload_total_bandwidth"].string().find('-') == string::npos) toApplay["virtualserver_max_upload_total_bandwidth"] = to_string((int64_t) cmd["virtualserver_max_upload_total_bandwidth"].as()); else toApplay["virtualserver_max_upload_total_bandwidth"] = to_string(cmd["virtualserver_max_upload_total_bandwidth"].as()); } SERVEREDIT_CHK_PROP2("virtualserver_download_quota", permission::b_virtualserver_modify_ft_quotas, uint64_t, int64_t) if(cmd["virtualserver_download_quota"].string().find('-') == string::npos) toApplay["virtualserver_download_quota"] = to_string((int64_t) cmd["virtualserver_download_quota"].as()); else toApplay["virtualserver_download_quota"] = to_string(cmd["virtualserver_download_quota"].as()); } SERVEREDIT_CHK_PROP2("virtualserver_upload_quota", permission::b_virtualserver_modify_ft_quotas, uint64_t, int64_t) if(cmd["virtualserver_upload_quota"].string().find('-') == string::npos) toApplay["virtualserver_upload_quota"] = to_string((int64_t) cmd["virtualserver_upload_quota"].as()); else toApplay["virtualserver_upload_quota"] = to_string(cmd["virtualserver_upload_quota"].as()); } else { logError(target_server ? target_server->getServerId() : 0, "Client " + this->getDisplayName() + " tried to change a not existing server properties. (" + key + ")"); //return command_result{error::not_implemented}; } } std::deque keys; bool group_update = false; for (const auto& elm : toApplay) { const auto& info = property::find(elm.first); if(info == property::VIRTUALSERVER_UNDEFINED) { logCritical(target_server ? target_server->getServerId() : 0, "Missing server property " + elm.first); continue; } if(!info.validate_input(elm.second)) { logError(target_server ? target_server->getServerId() : 0, "Client " + this->getDisplayName() + " tried to change a property to an invalid value. (Value: '" + elm.second + "', Property: '" + std::string{info.name} + "')"); continue; } if(target_server) target_server->properties()[info] = elm.second; else (*serverInstance->getDefaultServerProperties())[info] = elm.second; keys.push_back(elm.first); group_update |= info == property::VIRTUALSERVER_DEFAULT_SERVER_GROUP || info == property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP || info == property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP; } if(target_server) { if (group_update) target_server->forEachClient([&](const shared_ptr& client) { if(target_server->notifyClientPropertyUpdates(client, target_server->groups->update_server_group_property(client, true, client->getChannel()))) { if(client->update_cached_permissions()) /* update cached calculated permissions */ client->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ } }); if (!keys.empty()) target_server->notifyServerEdited(_this.lock(), keys); } return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerRequestConnectionInfo(Command &) { CMD_REQ_SERVER; ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_connectioninfo_view, 1); ts::command_builder result{"notifyserverconnectioninfo"}; auto first_bulk = result.bulk(0); auto total_stats = this->server->getServerStatistics()->total_stats(); auto minute_report = this->server->getServerStatistics()->minute_stats(); auto second_report = this->server->getServerStatistics()->second_stats(); auto network_report = this->server->generate_network_report(); first_bulk.put_unchecked(property::CONNECTION_FILETRANSFER_BANDWIDTH_SENT, minute_report.file_bytes_sent); first_bulk.put_unchecked(property::CONNECTION_FILETRANSFER_BANDWIDTH_RECEIVED, minute_report.file_bytes_received); first_bulk.put_unchecked(property::CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL, minute_report.file_bytes_sent); first_bulk.put_unchecked(property::CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL, minute_report.file_bytes_received); first_bulk.put_unchecked("connection_filetransfer_bytes_sent_month", this->server->properties()[property::VIRTUALSERVER_MONTH_BYTES_DOWNLOADED].as()); first_bulk.put_unchecked("connection_filetransfer_bytes_received_month", this->server->properties()[property::VIRTUALSERVER_MONTH_BYTES_UPLOADED].as()); first_bulk.put_unchecked(property::CONNECTION_PACKETS_SENT_TOTAL, std::accumulate(total_stats.connection_packets_sent.begin(), total_stats.connection_packets_sent.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_BYTES_SENT_TOTAL, std::accumulate(total_stats.connection_bytes_sent.begin(), total_stats.connection_bytes_sent.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_PACKETS_RECEIVED_TOTAL, std::accumulate(total_stats.connection_packets_received.begin(), total_stats.connection_packets_received.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_BYTES_RECEIVED_TOTAL, std::accumulate(total_stats.connection_bytes_received.begin(), total_stats.connection_bytes_received.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_BANDWIDTH_SENT_LAST_SECOND_TOTAL, std::accumulate(second_report.connection_bytes_sent.begin(), second_report.connection_bytes_sent.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_TOTAL, std::accumulate(minute_report.connection_bytes_sent.begin(), minute_report.connection_bytes_sent.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_TOTAL, std::accumulate(second_report.connection_bytes_received.begin(), second_report.connection_bytes_received.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_TOTAL, std::accumulate(minute_report.connection_bytes_received.begin(), minute_report.connection_bytes_received.end(), 0U)); first_bulk.put_unchecked(property::CONNECTION_CONNECTED_TIME, this->server->properties()[property::VIRTUALSERVER_UPTIME].as()); first_bulk.put_unchecked(property::CONNECTION_PACKETLOSS_TOTAL, network_report.average_loss); first_bulk.put_unchecked(property::CONNECTION_PING, network_report.average_ping); this->sendCommand(result); return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupList(Command &) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_list, 1); this->notifyServerGroupList(); this->command_times.servergrouplist = system_clock::now(); return command_result{error::ok}; } //servergroupadd name=TestGroup type=1 command_result ConnectedClient::handleCommandServerGroupAdd(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_create, 1); if(cmd["name"].string().empty()) return command_result{error::parameter_invalid}; if(cmd["type"].as() == GroupType::GROUP_TYPE_QUERY) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1); } else if(cmd["type"].as() == GroupType::GROUP_TYPE_TEMPLATE) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1); } else if(!this->server) return command_result{error::parameter_invalid, "you cant create normal groups on the template server!"}; auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get(); for(const auto& gr : group_manager->availableServerGroups(true)) if(gr->name() == cmd["name"].string() && gr->target() == GroupTarget::GROUPTARGET_SERVER) return command_result{error::parameter_invalid, "Group already exists"}; auto group = group_manager->createGroup(GroupTarget::GROUPTARGET_SERVER, cmd["type"].as(), cmd["name"].string()); if (group) { group->permissions()->set_permission(permission::b_group_is_permanent, {1,0}, permission::v2::set_value, permission::v2::do_nothing); if(this->server) this->server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); }); } else return command_result{error::vs_critical}; return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupCopy(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); auto ref_server = this->server; ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_create, 1); auto group_manager = this->server ? this->server->groups : serverInstance->getGroupManager().get(); auto source_group_id = cmd["ssgid"].as(); auto source_group = group_manager->findGroup(source_group_id); if(!source_group || source_group->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; const auto group_type_modificable = [&](GroupType type) { switch(type) { case GroupType::GROUP_TYPE_TEMPLATE: if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_templates, 0))) return permission::b_serverinstance_modify_templates; break; case GroupType::GROUP_TYPE_QUERY: if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_querygroup, 0))) return permission::b_serverinstance_modify_querygroup; break; default: break; } return permission::undefined; }; { auto result = group_type_modificable(source_group->type()); if(result != permission::undefined) return command_result{result}; } auto global_update = false; if(cmd[0].has("tsgid") && cmd["tsgid"].as() != 0) { //Copy an existing group auto target_group = group_manager->findGroup(cmd["tsgid"]); if(!target_group || target_group->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; { auto result = group_type_modificable(target_group->type()); if(result != permission::undefined) return command_result{result}; } if(!target_group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission(permission::i_server_group_modify_power, 0), true)) return command_result{permission::i_server_group_modify_power}; if(!group_manager->copyGroupPermissions(source_group, target_group)) return command_result{error::vs_critical, "failed to copy group permissions"}; global_update = !this->server || !group_manager->isLocalGroup(target_group); } else { //Copy a new group auto target_type = cmd["type"].as(); { auto result = group_type_modificable(target_type); if(result != permission::undefined) return command_result{result}; } if(!ref_server && target_type == GroupType::GROUP_TYPE_NORMAL) return command_result{error::parameter_invalid, "You cant create normal groups on the template server!"}; if(!group_manager->findGroup(GroupTarget::GROUPTARGET_SERVER, cmd["name"].string()).empty()) return command_result{error::group_name_inuse, "You cant create normal groups on the template server!"}; auto target_group_id = group_manager->copyGroup(source_group, target_type, cmd["name"], target_type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId()); if(target_group_id == 0) return command_result{error::vs_critical, "failed to copy group"}; if(this->getType() == ClientType::CLIENT_QUERY) { Command notify(""); notify["sgid"] = target_group_id; this->sendCommand(notify); } global_update = !this->server || !group_manager->isLocalGroup(group_manager->findGroup(target_group_id)); } for(const auto& server : (global_update ? serverInstance->getVoiceServerManager()->serverInstances() : deque>{this->server})) if(server) server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); }); return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupRename(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get(); auto serverGroup = group_manager->findGroup(cmd["sgid"].as()); if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, true); auto type = serverGroup->type(); if(type == GroupType::GROUP_TYPE_QUERY) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1); } else if(type == GroupType::GROUP_TYPE_TEMPLATE) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1); } group_manager->renameGroup(serverGroup, cmd["name"].string()); if(this->server) this->server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); }); return command_result{error::ok}; } //servergroupdel sgid=2 force=0 command_result ConnectedClient::handleCommandServerGroupDel(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_delete, 1); auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get(); auto serverGroup = group_manager->findGroup(cmd["sgid"].as()); if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; if(this->server && this->server->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] == serverGroup->groupId()) return command_result{error::parameter_invalid, "Could not delete default server group!"}; if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP] == serverGroup->groupId()) return command_result{error::parameter_invalid, "Could not delete instance default server admin group!"}; if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP] == serverGroup->groupId()) return command_result{error::parameter_invalid, "Could not delete instance default server group!"}; if(serverInstance->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP] == serverGroup->groupId()) return command_result{error::parameter_invalid, "Could not delete instance default guest server query group!"}; auto type = serverGroup->type(); if(type == GroupType::GROUP_TYPE_QUERY) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1); } else if(type == GroupType::GROUP_TYPE_TEMPLATE) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1); } if (!cmd["force"].as()) if (!group_manager->listGroupMembers(serverGroup, false).empty()) return command_result{error::database_empty_result, "group not empty!"}; if (group_manager->deleteGroup(serverGroup)) { if(this->server) this->server->forEachClient([&](shared_ptr cl) { if(this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) { if(cl->update_cached_permissions()) /* update cached calculated permissions */ cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ } cl->notifyServerGroupList(); }); } return command_result{error::ok}; } //servergroupclientlist sgid=2 //notifyservergroupclientlist sgid=6 cldbid=2 client_nickname=WolverinDEV client_unique_identifier=xxjnc14LmvTk+Lyrm8OOeo4tOqw= command_result ConnectedClient::handleCommandServerGroupClientList(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_client_list, 1); auto server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; auto groupManager = server ? this->server->groups : serverInstance->getGroupManager().get(); auto serverGroup = groupManager->findGroup(cmd["sgid"].as()); if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; Command notify(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifyservergroupclientlist" : ""); notify["sgid"] = cmd["sgid"].as(); int index = 0; for (const auto &clientEntry : groupManager->listGroupMembers(serverGroup)) { notify[index]["cldbid"] = clientEntry->cldbId; notify[index]["client_nickname"] = clientEntry->displayName; notify[index]["client_unique_identifier"] = clientEntry->uid; index++; } this->sendCommand(notify); return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(25); auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; auto group_manager = target_server ? this->server->groups : serverInstance->getGroupManager().get(); auto target_cldbid = cmd["cldbid"].as(); if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"}; auto needed_client_permission = this->server->calculate_permission(permission::i_client_needed_permission_modify_power, target_cldbid, ClientType::CLIENT_TEAMSPEAK, 0); if(needed_client_permission.has_value) { if(!permission::v2::permission_granted(needed_client_permission, this->calculate_permission(permission::i_client_permission_modify_power, 0))) return command_result{permission::i_client_needed_permission_modify_power}; } vector> target_groups; vector> applied_groups; target_groups.reserve(cmd.bulkCount()); auto continue_on_error = cmd.hasParm("continueonerror"); { auto permission_add_power = this->calculate_permission(permission::i_server_group_member_add_power, -1); auto permission_self_add_power = this->calculate_permission(permission::i_server_group_member_add_power, -1); for(auto index = 0; index < cmd.bulkCount(); index++) { auto group_id = cmd[index]["sgid"]; if(!group_id.castable() && continue_on_error) continue; auto gid = group_id.as(); auto group = group_manager->findGroup(gid); if(!group) { if(continue_on_error) continue; return command_result{error::group_invalid_id}; } if(!target_server && group->target() != GroupTarget::GROUPTARGET_SERVER && group->type() != GroupType::GROUP_TYPE_QUERY) return command_result{error::parameter_invalid}; if(find(target_groups.begin(), target_groups.end(), group) != target_groups.end()) { if(continue_on_error) continue; return command_result{error::client_is_already_member_of_group}; } /* permission tests */ if(!group->permission_granted(permission::i_server_group_needed_member_add_power, permission_add_power, true)) { if(target_cldbid != this->getClientDatabaseId()) { if(continue_on_error) continue; return command_result{permission::i_server_group_member_add_power}; } if(!group->permission_granted(permission::i_server_group_needed_member_add_power, permission_self_add_power, true)) { if(continue_on_error) continue; return command_result{permission::i_server_group_self_add_power}; } } target_groups.push_back(std::move(group)); } } applied_groups.reserve(target_groups.size()); if(target_groups.empty()) return command_result{error::ok}; else if(target_groups.size() == 1) { /* speed up thing, don't try to load any cache */ auto group = target_groups[0]; if(group_manager->hasServerGroupAssigned(target_cldbid, group)) return command_result{error::client_is_already_member_of_group}; group_manager->addServerGroup(target_cldbid, group); applied_groups.push_back(group); } else { group_manager->enableCache(target_cldbid); scope_exit_callback cache_disable{[group_manager, target_cldbid]{ group_manager->disableCache(target_cldbid); }}; for(const auto& group : target_groups) { if(group_manager->hasServerGroupAssigned(target_cldbid, group)) { if(continue_on_error) continue; return command_result{error::client_is_already_member_of_group}; } group_manager->addServerGroup(target_cldbid, group); applied_groups.push_back(group); } } for(const auto& _server : target_server ? std::deque>{target_server} : serverInstance->getVoiceServerManager()->serverInstances()) { for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) { if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient, true, targetClient->getChannel()))) { for (const auto &client : _server->getClients()) { if(client->isClientVisible(targetClient, true) || client == targetClient) for(const auto& group : applied_groups) client->notifyServerGroupClientAdd(_this.lock(), targetClient, group); } if(targetClient->update_cached_permissions()) /* update cached calculated permissions */ targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ targetClient->updateChannelClientProperties(true, true); } } } return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(25); auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; auto group_manager = target_server ? this->server->groups : serverInstance->getGroupManager().get(); auto target_cldbid = cmd["cldbid"].as(); if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"}; auto needed_client_permission = this->server->calculate_permission(permission::i_client_needed_permission_modify_power, target_cldbid, ClientType::CLIENT_TEAMSPEAK, 0); if(needed_client_permission.has_value) { if(!permission::v2::permission_granted(needed_client_permission, this->calculate_permission(permission::i_client_permission_modify_power, 0))) return command_result{permission::i_client_needed_permission_modify_power}; } vector> target_groups; vector> applied_groups; target_groups.reserve(cmd.bulkCount()); auto continue_on_error = cmd.hasParm("continueonerror"); { auto permission_remove_power = this->calculate_permission(permission::i_server_group_member_remove_power, -1); auto permission_self_remove_power = this->calculate_permission(permission::i_server_group_member_remove_power, -1); for(auto index = 0; index < cmd.bulkCount(); index++) { auto group_id = cmd[index]["sgid"]; if(!group_id.castable() && continue_on_error) continue; auto gid = group_id.as(); auto group = group_manager->findGroup(gid); if(!group) { if(continue_on_error) continue; return command_result{error::group_invalid_id}; } if(!target_server && group->target() != GroupTarget::GROUPTARGET_SERVER && group->type() != GroupType::GROUP_TYPE_QUERY) return command_result{error::group_invalid_id}; if(find(target_groups.begin(), target_groups.end(), group) != target_groups.end()) { if(continue_on_error) continue; return command_result{error::parameter_invalid, "duplicate server group for id " + to_string(gid)}; } /* permission tests */ if(!group->permission_granted(permission::i_server_group_needed_member_remove_power, permission_remove_power, true)) { if(target_cldbid != this->getClientDatabaseId()) { if(continue_on_error) continue; return command_result{permission::i_server_group_member_remove_power}; } if(!group->permission_granted(permission::i_server_group_needed_member_remove_power, permission_self_remove_power, true)) { if(continue_on_error) continue; return command_result{permission::i_server_group_self_remove_power}; } } target_groups.push_back(std::move(group)); } } applied_groups.reserve(target_groups.size()); if(target_groups.empty()) return command_result{error::ok}; else if(target_groups.size() == 1) { /* speed up thing, don't try to load any cache */ auto group = target_groups[0]; auto assignment = group_manager->get_group_assignment(target_cldbid, group); if(!assignment) { return command_result{error::client_is_not_member_of_group}; } if(assignment->server != (target_server ? target_server->getServerId() : 0)) { return command_result{error::group_not_assigned_over_this_server}; } group_manager->removeServerGroup(target_cldbid, group); applied_groups.push_back(group); } else { group_manager->enableCache(target_cldbid); scope_exit_callback cache_disable{[group_manager, target_cldbid]{ group_manager->disableCache(target_cldbid); }}; for(const auto& group : target_groups) { auto assignment = group_manager->get_group_assignment(target_cldbid, group); if(!assignment) { if(continue_on_error) continue; return command_result{error::client_is_not_member_of_group}; } if(assignment->server != (target_server ? target_server->getServerId() : 0)) { if(continue_on_error) continue; return command_result{error::group_not_assigned_over_this_server}; } applied_groups.push_back(group); group_manager->removeServerGroup(target_cldbid, group); } } for(const auto& _server : target_server ? std::deque>{target_server} : serverInstance->getVoiceServerManager()->serverInstances()) { for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) { if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient, true, targetClient->getChannel()))) { for (const auto &client : _server->getClients()) { if(client->isClientVisible(targetClient, true) || client == targetClient) for(const auto& group : applied_groups) client->notifyServerGroupClientRemove(_this.lock(), targetClient, group); } if(targetClient->update_cached_permissions()) /* update cached calculated permissions */ targetClient->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ targetClient->updateChannelClientProperties(true, true); } } } return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupPermList(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_permission_list, 1); auto serverGroup = (this->server ? this->server->groups : serverInstance->getGroupManager().get())->findGroup(cmd["sgid"].as()); if (!serverGroup) return command_result{error::group_invalid_id}; if(this->getType() == ClientType::CLIENT_TEAMSPEAK && this->command_times.last_notify + this->command_times.notify_timeout < system_clock::now()) { this->sendTSPermEditorWarning(); } if (!this->notifyGroupPermList(serverGroup, cmd.hasParm("permsid"))) return command_result{error::database_empty_result}; return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); auto serverGroup = (this->server ? this->server->groups : serverInstance->getGroupManager().get())->findGroup(cmd["sgid"].as()); if (!serverGroup) return command_result{error::group_invalid_id}; if (serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, 1); auto type = serverGroup->type(); if(type == GroupType::GROUP_TYPE_QUERY) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1); } else if(type == GroupType::GROUP_TYPE_TEMPLATE) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1); } auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true); if(!max_value.has_value) return command_result{permission::i_permission_modify_power}; auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0)); bool conOnError = cmd[0].has("continueonerror"); bool checkTp = false; bool sgroupUpdate = false; auto permissions = serverGroup->permissions(); for (int index = 0; index < cmd.bulkCount(); index++) { PARSE_PERMISSION(cmd); //permvalue='1' permnegated='0' permskip='0' auto val = cmd[index]["permvalue"].as(); if(permission_require_granted_value(permType) && !permission::v2::permission_granted(val, max_value)) { if(conOnError) continue; return command_result{permission::i_permission_modify_power}; } if(!ignore_granted_values && !permission::v2::permission_granted(1, this->calculate_permission(permType, 0, true))) { if(conOnError) continue; return command_result{permission::i_permission_modify_power}; } if (grant) { permissions->set_permission(permType, {0, cmd[index]["permvalue"]}, permission::v2::PermissionUpdateType::do_nothing, permission::v2::PermissionUpdateType::set_value); } else { permissions->set_permission( permType, {cmd[index]["permvalue"], 0}, permission::v2::PermissionUpdateType::set_value, permission::v2::PermissionUpdateType::do_nothing, cmd[index]["permskip"].as() ? 1 : 0, cmd[index]["permnegated"].as() ? 1 : 0 ); sgroupUpdate |= permission_is_group_property(permType); checkTp |= permission_is_client_property(permType); } } if(sgroupUpdate) serverGroup->apply_properties_from_permissions(); //TODO may update for every server? if(this->server) { auto lock = this->_this.lock(); auto server = this->server; threads::Thread([checkTp, sgroupUpdate, serverGroup, lock, server]() { if(sgroupUpdate) server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); }); server->forEachClient([serverGroup, checkTp](shared_ptr cl) { if (cl->serverGroupAssigned(serverGroup)) { if(cl->update_cached_permissions()) /* update cached calculated permissions */ cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ if (checkTp) cl->updateChannelClientProperties(true, true); cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ } }); }).detach(); } return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupDelPerm(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); auto serverGroup = (this->server ? this->server->groups : serverInstance->getGroupManager().get())->findGroup(cmd["sgid"].as()); if (!serverGroup) return command_result{error::group_invalid_id}; if (serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, 1); auto type = serverGroup->type(); if(type == GroupType::GROUP_TYPE_QUERY) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1); } else if(type == GroupType::GROUP_TYPE_TEMPLATE) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1); } auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0)); bool conOnError = cmd[0].has("continueonerror"); bool checkTp = false; auto sgroupUpdate = false; for (int index = 0; index < cmd.bulkCount(); index++) { PARSE_PERMISSION(cmd); if(!ignore_granted_values && !permission::v2::permission_granted(0, this->calculate_permission(permType, 0, true))) { if(conOnError) continue; return command_result{permission::i_permission_modify_power}; } if (grant) { serverGroup->permissions()->set_permission(permType, permission::v2::empty_permission_values, permission::v2::PermissionUpdateType::do_nothing, permission::v2::PermissionUpdateType::delete_value); } else { serverGroup->permissions()->set_permission( permType, permission::v2::empty_permission_values, permission::v2::PermissionUpdateType::delete_value, permission::v2::PermissionUpdateType::do_nothing ); sgroupUpdate |= permission_is_group_property(permType); checkTp |= permission_is_client_property(permType); } } if(sgroupUpdate) serverGroup->apply_properties_from_permissions(); if(this->server) { auto lock = this->_this.lock(); auto server = this->server; threads::Thread([checkTp, sgroupUpdate, serverGroup, lock, server]() { if(sgroupUpdate) server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); }); server->forEachClient([serverGroup, checkTp](shared_ptr cl) { if (cl->serverGroupAssigned(serverGroup)) { if(cl->update_cached_permissions()) /* update cached calculated permissions */ cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ if (checkTp) cl->updateChannelClientProperties(true, true); cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ } }); }).detach(); } return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command& cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(25); auto ref_server = this->server; auto group_manager = ref_server ? this->server->groups : &*serverInstance->getGroupManager(); deque> groups; for(const auto& group : group_manager->availableGroups(false)) { if(group->updateType() == cmd["sgtype"].as() && group->target() == GROUPTARGET_SERVER) { if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission(permission::i_server_group_modify_power, 0), true)) { auto type = group->type(); if(type == GroupType::GROUP_TYPE_QUERY) { if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_querygroup, 0))) continue; } else if(type == GroupType::GROUP_TYPE_TEMPLATE) { if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_templates, 0))) continue; } groups.push_back(group);//sgtype } } } if(groups.empty()) return command_result{error::ok}; auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true); if(!max_value.has_value) return command_result{permission::i_permission_modify_power}; auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0)); bool conOnError = cmd[0].has("continueonerror"); bool checkTp = false; bool sgroupUpdate = false; for (int index = 0; index < cmd.bulkCount(); index++) { PARSE_PERMISSION(cmd); //permvalue='1' permnegated='0' permskip='0'end auto val = cmd[index]["permvalue"].as(); if(permission_require_granted_value(permType) && !permission::v2::permission_granted(val, max_value)) { if(conOnError) continue; return command_result{permission::i_permission_modify_power}; } if(!ignore_granted_values && !permission::v2::permission_granted(1, this->calculate_permission(permType, 0, true))) { if(conOnError) continue; return command_result{permission::i_permission_modify_power}; } for(const auto& serverGroup : groups) { if (grant) { serverGroup->permissions()->set_permission(permType, {0, cmd[index]["permvalue"]}, permission::v2::PermissionUpdateType::do_nothing, permission::v2::PermissionUpdateType::set_value); } else { serverGroup->permissions()->set_permission( permType, {cmd[index]["permvalue"], 0}, permission::v2::PermissionUpdateType::set_value, permission::v2::PermissionUpdateType::do_nothing, cmd[index]["permskip"].as() ? 1 : 0, cmd[index]["permnegated"].as() ? 1 : 0 ); } } sgroupUpdate |= permission_is_group_property(permType); checkTp |= permission_is_client_property(permType); } if(sgroupUpdate) for(auto& group : groups) group->apply_properties_from_permissions(); auto lock = this->_this.lock(); if(ref_server) { threads::Thread([checkTp, sgroupUpdate, groups, lock, ref_server]() { if(sgroupUpdate) ref_server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); }); ref_server->forEachClient([groups, checkTp](shared_ptr cl) { for(const auto& serverGroup : groups) { if (cl->serverGroupAssigned(serverGroup)) { if(cl->update_cached_permissions()) {/* update cached calculated permissions */ cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ } if (checkTp) { cl->updateChannelClientProperties(true, true); } cl->join_state_id++; /* join permission may changed, all channels need to be recalculate if needed */ break; } } }); }).detach(); } return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command& cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(25); auto ref_server = this->server; auto group_manager = ref_server ? this->server->groups : &*serverInstance->getGroupManager(); deque> groups; for(const auto& group : group_manager->availableGroups(false)) { if(group->updateType() == cmd["sgtype"].as() && group->target() == GROUPTARGET_SERVER) { if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission(permission::i_server_group_modify_power, 0), true)) { auto type = group->type(); if(type == GroupType::GROUP_TYPE_QUERY) { if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_querygroup, 0))) continue; } else if(type == GroupType::GROUP_TYPE_TEMPLATE) { if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_serverinstance_modify_templates, 0))) continue; } groups.push_back(group);//sgtype } } } if(groups.empty()) return command_result{error::ok}; auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0)); bool conOnError = cmd[0].has("continueonerror"); bool checkTp = false; auto sgroupUpdate = false; for (int index = 0; index < cmd.bulkCount(); index++) { PARSE_PERMISSION(cmd); if(!ignore_granted_values && !permission::v2::permission_granted(0, this->calculate_permission(permType, 0, true))) { if(conOnError) continue; return command_result{permission::i_permission_modify_power}; } for(const auto& serverGroup : groups) { if (grant) { serverGroup->permissions()->set_permission(permType, permission::v2::empty_permission_values, permission::v2::PermissionUpdateType::do_nothing, permission::v2::PermissionUpdateType::delete_value); } else { serverGroup->permissions()->set_permission( permType, permission::v2::empty_permission_values, permission::v2::PermissionUpdateType::delete_value, permission::v2::PermissionUpdateType::do_nothing ); sgroupUpdate |= permission_is_group_property(permType); } } checkTp |= permission_is_client_property(permType); } if(sgroupUpdate) { for(auto& group : groups) group->apply_properties_from_permissions(); } if(ref_server) { auto lock = this->_this.lock(); threads::Thread([checkTp, sgroupUpdate, groups, lock, ref_server]() { if(sgroupUpdate) ref_server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); }); ref_server->forEachClient([groups, checkTp](shared_ptr cl) { for(const auto& serverGroup : groups) { if (cl->serverGroupAssigned(serverGroup)) { if(cl->update_cached_permissions()) /* update cached calculated permissions */ cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */ if (checkTp) cl->updateChannelClientProperties(true, true); cl->join_state_id++; /* join permission may changed, all channels need to be recalculate dif needed */ break; } } }); }).detach(); } return command_result{error::ok}; } command_result ConnectedClient::handleCommandServerGroupsByClientId(Command &cmd) { CMD_RESET_IDLE; ClientDbId cldbid = cmd["cldbid"]; if(!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cldbid)) return command_result{error::client_invalid_id}; Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyservergroupsbyclientid" : ""); int index = 0; if (this->server) { for (const auto &group : this->server->groups->getAssignedServerGroups(cldbid)) { result[index]["name"] = group->group->name(); result[index]["sgid"] = group->group->groupId(); result[index]["cldbid"] = cldbid; index++; } } else { for (const auto &group : serverInstance->getGroupManager()->getAssignedServerGroups(cldbid)) { result[index]["name"] = group->group->name(); result[index]["sgid"] = group->group->groupId(); result[index]["cldbid"] = cldbid; index++; } } if (index == 0) return command_result{error::database_empty_result}; this->sendCommand(result); return command_result{error::ok}; }