/* * Copyright (C) 2008-2013 TrinityCore * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "RBAC.h" #include "AccountMgr.h" #include "DatabaseEnv.h" void RBACRole::GrantPermission(uint32 permissionId) { if (permissionId < RBAC_PERM_MAX) { sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Ok", GetId(), permissionId); _perms.set(permissionId); } else sLog->outError(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Permission not lower than %u", GetId(), permissionId, RBAC_PERM_MAX); } void RBACRole::RevokePermission(uint32 permissionId) { if (permissionId < RBAC_PERM_MAX) { sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::RevokePermission (Role %u, Permission %u). Ok", GetId(), permissionId); _perms.reset(permissionId); } else sLog->outError(LOG_FILTER_RBAC, "RBACRole::RevokePermission (Role %u, Permission %u). Permission not lower than %u", GetId(), permissionId, RBAC_PERM_MAX); } void RBACGroup::GrantRole(uint32 roleId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Ok", GetId(), roleId); _roles.insert(roleId); } void RBACGroup::RevokeRole(uint32 roleId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Ok", GetId(), roleId); _roles.erase(roleId); } RBACCommandResult RBACData::AddGroup(uint32 groupId, int32 realmId /* = 0 */) { // Check if group Id exists RBACGroup const* group = sAccountMgr->GetRBACGroup(groupId); if (!group) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Group does not exists", GetId(), GetName().c_str(), groupId, realmId); return RBAC_ID_DOES_NOT_EXISTS; } // Already added? std::pair::iterator, bool> ret = _groups.insert(groupId); if (!ret.second) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Group Already added", GetId(), GetName().c_str(), groupId, realmId); return RBAC_CANT_ADD_ALREADY_ADDED; } // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Added and DB updated", GetId(), GetName().c_str(), groupId, realmId); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_GROUP); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, groupId); stmt->setInt32(2, realmId); LoginDatabase.Execute(stmt); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Added", GetId(), GetName().c_str(), groupId, realmId); return RBAC_OK; } RBACCommandResult RBACData::RemoveGroup(uint32 groupId, int32 realmId /* = 0 */) { // could remove it? if (!_groups.erase(groupId)) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RemoveGroup [Id: %u Name: %s] (Group %u, RealmId %d). Group not in list", GetId(), GetName().c_str(), groupId, realmId); return RBAC_CANT_REVOKE_NOT_IN_LIST; } // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RemoveGroup [Id: %u Name: %s] (Group %u, RealmId %d). Removed and DB updated", GetId(), GetName().c_str(), groupId, realmId); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_GROUP); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, groupId); stmt->setInt32(2, realmId); LoginDatabase.Execute(stmt); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RemoveGroup [Id: %u Name: %s] (Group %u, RealmId %d). Removed", GetId(), GetName().c_str(), groupId, realmId); return RBAC_OK; } RBACCommandResult RBACData::GrantRole(uint32 roleId, int32 realmId /* = 0*/) { // Check if role Id exists RBACRole const* role = sAccountMgr->GetRBACRole(roleId); if (!role) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Role does not exists", GetId(), GetName().c_str(), roleId, realmId); return RBAC_ID_DOES_NOT_EXISTS; } // Check if already added in denied list if (_deniedRoles.find(roleId) != _deniedRoles.end()) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Role in deny list", GetId(), GetName().c_str(), roleId, realmId); return RBAC_IN_DENIED_LIST; } // Already added? std::pair::iterator, bool> ret = _grantedRoles.insert(roleId); if (!ret.second) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Role already granted", GetId(), GetName().c_str(), roleId, realmId); return RBAC_CANT_ADD_ALREADY_ADDED; } // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok and DB updated", GetId(), GetName().c_str(), roleId, realmId); SaveRole(roleId, true, realmId); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok", GetId(), GetName().c_str(), roleId, realmId); return RBAC_OK; } RBACCommandResult RBACData::DenyRole(uint32 roleId, int32 realmId /* = 0*/) { // Check if role Id exists RBACRole const* role = sAccountMgr->GetRBACRole(roleId); if (!role) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Role does not exists", GetId(), GetName().c_str(), roleId, realmId); return RBAC_ID_DOES_NOT_EXISTS; } // Check if already added in granted list if (_grantedRoles.find(roleId) != _grantedRoles.end()) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Role in grant list", GetId(), GetName().c_str(), roleId, realmId); return RBAC_IN_GRANTED_LIST; } // Already added? std::pair::iterator, bool> ret = _deniedRoles.insert(roleId); if (!ret.second) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Role already denied", GetId(), GetName().c_str(), roleId, realmId); return RBAC_CANT_ADD_ALREADY_ADDED; } // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok and DB updated", GetId(), GetName().c_str(), roleId, realmId); SaveRole(roleId, false, realmId); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok", GetId(), GetName().c_str(), roleId, realmId); return RBAC_OK; } void RBACData::SaveRole(uint32 roleId, bool granted, int32 realmId) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_ROLE); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, roleId); stmt->setBool(2, granted); stmt->setInt32(3, realmId); LoginDatabase.Execute(stmt); } RBACCommandResult RBACData::RevokeRole(uint32 roleId, int32 realmId /* = 0*/) { uint8 revoked = _grantedRoles.erase(roleId) + _deniedRoles.erase(roleId); // could remove it? if (!revoked) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokeRole [Id: %u Name: %s] (Role %u, RealmId %d). Not granted or revoked", GetId(), GetName().c_str(), roleId, realmId); return RBAC_CANT_REVOKE_NOT_IN_LIST; } // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokeRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok and DB updated", GetId(), GetName().c_str(), roleId, realmId); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_ROLE); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, roleId); stmt->setInt32(2, realmId); LoginDatabase.Execute(stmt); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokeRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok", GetId(), GetName().c_str(), roleId, realmId); return RBAC_OK; } RBACCommandResult RBACData::GrantPermission(uint32 permissionId, int32 realmId /* = 0*/) { // Check if permission Id exists RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId); if (!perm) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission does not exists", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_ID_DOES_NOT_EXISTS; } // Check if already added in denied list if (_deniedPerms.test(permissionId)) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission in deny list", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_IN_DENIED_LIST; } // Already added? if (_grantedPerms.test(permissionId)) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission already granted", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_CANT_ADD_ALREADY_ADDED; } _grantedPerms.set(permissionId); // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok and DB updated", GetId(), GetName().c_str(), permissionId, realmId); SavePermission(permissionId, true, realmId); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_OK; } RBACCommandResult RBACData::DenyPermission(uint32 permissionId, int32 realmId /* = 0*/) { // Check if permission Id exists RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId); if (!perm) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission does not exists", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_ID_DOES_NOT_EXISTS; } // Check if already added in granted list if (_grantedPerms.test(permissionId)) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission in grant list", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_IN_GRANTED_LIST; } // Already added? if (_deniedPerms.test(permissionId)) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission already denied", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_CANT_ADD_ALREADY_ADDED; } _deniedPerms.set(permissionId); // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok and DB updated", GetId(), GetName().c_str(), permissionId, realmId); SavePermission(permissionId, false, realmId); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_OK; } void RBACData::SavePermission(uint32 permission, bool granted, int32 realmId) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, permission); stmt->setBool(2, granted); stmt->setInt32(3, realmId); LoginDatabase.Execute(stmt); } RBACCommandResult RBACData::RevokePermission(uint32 permissionId, int32 realmId /* = 0*/) { // Check if it's present in any list if (!_grantedPerms.test(permissionId) && !_deniedPerms.test(permissionId)) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokePermission [Id: %u Name: %s] (Permission %u, RealmId %d). Not granted or revoked", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_CANT_REVOKE_NOT_IN_LIST; } _grantedPerms.reset(permissionId); _deniedPerms.reset(permissionId); // Do not save to db when loading data from DB (realmId = 0) if (realmId) { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokePermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok and DB updated", GetId(), GetName().c_str(), permissionId, realmId); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION); stmt->setUInt32(0, GetId()); stmt->setUInt32(1, permissionId); stmt->setInt32(2, realmId); LoginDatabase.Execute(stmt); CalculateNewPermissions(); } else sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokePermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok", GetId(), GetName().c_str(), permissionId, realmId); return RBAC_OK; } void RBACData::LoadFromDB() { sLog->outInfo(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]", GetId(), GetName().c_str()); sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Loading groups", GetId(), GetName().c_str()); // Load account group that affect current realm PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_GROUPS); stmt->setUInt32(0, GetId()); stmt->setInt32(1, GetRealmId()); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) { do { Field* fields = result->Fetch(); AddGroup(fields[0].GetUInt32()); } while (result->NextRow()); } sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Loading roles", GetId(), GetName().c_str()); // Load account roles (granted and denied) that affect current realm stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_ROLES); stmt->setUInt32(0, GetId()); stmt->setInt32(1, GetRealmId()); result = LoginDatabase.Query(stmt); if (result) { do { Field* fields = result->Fetch(); if (fields[1].GetBool()) GrantRole(fields[0].GetUInt32()); else DenyRole(fields[0].GetUInt32()); } while (result->NextRow()); } sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Loading permissions", GetId(), GetName().c_str()); // Load account permissions (granted and denied) that affect current realm stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS); stmt->setUInt32(0, GetId()); stmt->setInt32(1, GetRealmId()); result = LoginDatabase.Query(stmt); if (result) { do { Field* fields = result->Fetch(); if (fields[1].GetBool()) GrantPermission(fields[0].GetUInt32()); else DenyPermission(fields[0].GetUInt32()); } while (result->NextRow()); } sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Adding default groups", GetId(), GetName().c_str()); // Add default groups RBACGroupContainer const& groups = sAccountMgr->GetRBACDefaultGroups(); for (RBACGroupContainer::const_iterator itr = groups.begin(); itr != groups.end(); ++itr) AddGroup(*itr); sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Calculating global permissions", GetId(), GetName().c_str()); // Force calculation of permissions, it wasn't performed at load time // while adding groups, roles and permissions CalculateNewPermissions(); } void RBACData::CalculateNewPermissions() { sLog->outTrace(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Calculating global permissions", GetId(), GetName().c_str()); // Get the list of directly granted roles RBACRoleContainer tempGrantedRoles = GetGrantedRoles(); // Add those roles inherited from groups for (RBACGroupContainer::const_iterator itGroup = _groups.begin(); itGroup != _groups.end(); ++itGroup) { RBACGroup const* group = sAccountMgr->GetRBACGroup(*itGroup); if (!group) // Should never happen due to foreign keys in DB continue; RBACRoleContainer const& roles = group->GetRoles(); for (RBACRoleContainer::const_iterator it = roles.begin(); it != roles.end(); ++it) tempGrantedRoles.insert(*it); } // Get the list of granted permissions _globalPerms = GetGrantedPermissions(); // Add those permissions inherited from roles granted for (RBACRoleContainer::const_iterator it = tempGrantedRoles.begin(); it != tempGrantedRoles.end(); ++it) if (RBACRole const* role = sAccountMgr->GetRBACRole(*it)) _globalPerms |= role->GetPermissions(); // Remove denied permissions from the list _globalPerms &= ~GetDeniedPermissions(); // Remove those permissions inherited from denied roles for (RBACRoleContainer::const_iterator it = _deniedRoles.begin(); it != _deniedRoles.end(); ++it) if (RBACRole const* role = sAccountMgr->GetRBACRole(*it)) _globalPerms &= ~role->GetPermissions(); }