From 9c726fb178ce329e44fca9bca79a858f8a9ff4ae Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 9 Jun 2009 08:15:34 +0000 Subject: [PATCH] Thank you Snoopy, for a patch that implements group permissions. Applied with changes: - removed spammy debug message - corrected tab formatting --- .../World/Permissions/PermissionsModule.cs | 377 ++++++++++++------ .../Framework/Scenes/Scene.Inventory.cs | 27 +- 2 files changed, 264 insertions(+), 140 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 9298380b43..036c4b8f41 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -36,6 +36,56 @@ using OpenSim.Framework.Communications.Cache; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +// Temporary fix of wrong GroupPowers constants in OpenMetaverse library +enum GroupPowers : long + { + None = 0, + LandEjectAndFreeze = 1, + Invite = 2, + ReturnGroupSet = 2, + Eject = 4, + ReturnNonGroup = 4, + ChangeOptions = 8, + LandGardening = 8, + CreateRole = 16, + DeedObject = 16, + ModerateChat = 32, + DeleteRole = 32, + RoleProperties = 64, + ObjectManipulate = 64, + ObjectSetForSale = 128, + AssignMemberLimited = 128, + AssignMember = 256, + Accountable = 256, + RemoveMember = 512, + SendNotices = 1024, + ChangeActions = 1024, + ChangeIdentity = 2048, + ReceiveNotices = 2048, + StartProposal = 4096, + LandDeed = 4096, + VoteOnProposal = 8192, + LandRelease = 8192, + LandSetSale = 16384, + LandDivideJoin = 32768, + ReturnGroupOwned = 65536, + JoinChat = 65536, + FindPlaces = 131072, + LandChangeIdentity = 262144, + SetLandingPoint = 524288, + ChangeMedia = 1048576, + LandEdit = 2097152, + LandOptions = 4194304, + AllowEditLand = 8388608, + AllowFly = 16777216, + AllowRez = 33554432, + AllowLandmark = 67108864, + AllowVoiceChat = 134217728, + AllowSetHome = 268435456, + LandManageAllowed = 536870912, + LandManageBanned = 1073741824 + } + namespace OpenSim.Region.CoreModules.World.Permissions { public class PermissionsModule : IRegionModule @@ -62,7 +112,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions All, Administrators }; - + #endregion #region Bypass Permissions / Debug Permissions Stuff @@ -192,38 +242,38 @@ namespace OpenSim.Region.CoreModules.World.Permissions HandleDebugPermissions); - string grant = myConfig.GetString("GrantLSL",""); - if(grant.Length > 0) { - foreach (string uuidl in grant.Split(',')) { - string uuid = uuidl.Trim(" \t".ToCharArray()); - GrantLSL.Add(uuid, true); - } + string grant = myConfig.GetString("GrantLSL",""); + if(grant.Length > 0) { + foreach (string uuidl in grant.Split(',')) { + string uuid = uuidl.Trim(" \t".ToCharArray()); + GrantLSL.Add(uuid, true); + } } - grant = myConfig.GetString("GrantCS",""); - if(grant.Length > 0) { - foreach (string uuidl in grant.Split(',')) { - string uuid = uuidl.Trim(" \t".ToCharArray()); - GrantCS.Add(uuid, true); - } + grant = myConfig.GetString("GrantCS",""); + if(grant.Length > 0) { + foreach (string uuidl in grant.Split(',')) { + string uuid = uuidl.Trim(" \t".ToCharArray()); + GrantCS.Add(uuid, true); + } } - grant = myConfig.GetString("GrantVB",""); - if(grant.Length > 0) { - foreach (string uuidl in grant.Split(',')) { - string uuid = uuidl.Trim(" \t".ToCharArray()); - GrantVB.Add(uuid, true); - } + grant = myConfig.GetString("GrantVB",""); + if(grant.Length > 0) { + foreach (string uuidl in grant.Split(',')) { + string uuid = uuidl.Trim(" \t".ToCharArray()); + GrantVB.Add(uuid, true); + } } - grant = myConfig.GetString("GrantJS",""); - if(grant.Length > 0) { - foreach (string uuidl in grant.Split(',')) { - string uuid = uuidl.Trim(" \t".ToCharArray()); - GrantJS.Add(uuid, true); - } + grant = myConfig.GetString("GrantJS",""); + if(grant.Length > 0) { + foreach (string uuidl in grant.Split(',')) { + string uuid = uuidl.Trim(" \t".ToCharArray()); + GrantJS.Add(uuid, true); + } } - + } public void HandleBypassPermissions(string module, string[] args) @@ -328,7 +378,17 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (m_debugPermissions) m_log.Debug("[PERMISSIONS]: " + permissionCalled + " was called from " + m_scene.RegionInfo.RegionName); } - + + // Checks if the given group is active and if the user is a group member + // with the powers requested (powers = 0 for no powers check) + protected bool IsGroupMember(UUID groupID, UUID userID, ulong powers) + { + IClientAPI client = m_scene.GetScenePresence(userID).ControllingClient; + + return ((groupID == client.ActiveGroupId) && (client.ActiveGroupPowers != 0) && + ((powers == 0) || ((client.ActiveGroupPowers & powers) == powers))); + } + /// /// Parse a user set configuration setting /// @@ -371,6 +431,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions /// protected bool IsAdministrator(UUID user) { + if (user == UUID.Zero) return false; + if (m_scene.RegionInfo.MasterAvatarAssignedUUID != UUID.Zero) { if (m_RegionOwnerIsGod && (m_scene.RegionInfo.MasterAvatarAssignedUUID == user)) @@ -391,10 +453,6 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (profile.UserProfile.GodLevel >= 200) return true; } - //else - //{ - // m_log.ErrorFormat("[PERMISSIONS]: Could not find user {0} for administrator check", user); - //} } return false; @@ -402,6 +460,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions protected bool IsEstateManager(UUID user) { + if (user == UUID.Zero) return false; + return m_scene.RegionInfo.EstateSettings.IsEstateManager(user); } #endregion @@ -473,57 +533,39 @@ namespace OpenSim.Region.CoreModules.World.Permissions objectOwnerMask |= (uint)PrimFlags.ObjectYouOwner | (uint)PrimFlags.ObjectAnyOwner | (uint)PrimFlags.ObjectOwnerModify; // Customize the GroupMask - // uint objectGroupMask = ApplyObjectModifyMasks(task.GroupMask, objflags); + uint objectGroupMask = ApplyObjectModifyMasks(task.GroupMask, objflags); // Customize the EveryoneMask uint objectEveryoneMask = ApplyObjectModifyMasks(task.EveryoneMask, objflags); - - // Hack to allow collaboration until Groups and Group Permissions are implemented - if ((objectEveryoneMask & (uint)PrimFlags.ObjectMove) != 0) - objectEveryoneMask |= (uint)PrimFlags.ObjectModify; - if (m_bypassPermissions) return objectOwnerMask; - + // Object owners should be able to edit their own content if (user == objectOwner) - { return objectOwnerMask; - } - - //// Users should be able to edit what is over their land. - //ILandObject parcel = m_scene.LandChannel.GetLandObject(task.AbsolutePosition.X, task.AbsolutePosition.Y); - //if (parcel != null && parcel.landData.OwnerID == user && m_ParcelOwnerIsGod) - // return objectOwnerMask; - - //// Admin objects should not be editable by the above - //if (IsAdministrator(objectOwner)) - // return objectEveryoneMask; // Estate users should be able to edit anything in the sim - if (IsEstateManager(user) && m_RegionOwnerIsGod && (!IsAdministrator(objectOwner))) + if (IsEstateManager(user) && m_RegionOwnerIsGod && !IsAdministrator(objectOwner)) return objectOwnerMask; // Admin should be able to edit anything in the sim (including admin objects) if (IsAdministrator(user)) return objectOwnerMask; - + // Users should be able to edit what is over their land. ILandObject parcel = m_scene.LandChannel.GetLandObject(task.AbsolutePosition.X, task.AbsolutePosition.Y); if (parcel != null && parcel.landData.OwnerID == user && m_ParcelOwnerIsGod) { - uint responseMask = objectOwnerMask; - // Admin objects should not be editable by the above - if (IsAdministrator(objectOwner)) - { - responseMask = objectEveryoneMask; - } - - return responseMask; + if (!IsAdministrator(objectOwner)) + return objectOwnerMask; } + // Group permissions + if ( ( task.GroupID != UUID.Zero) && IsGroupMember(task.GroupID, user, 0) ) + return objectGroupMask; + return objectEveryoneMask; } @@ -607,6 +649,13 @@ namespace OpenSim.Region.CoreModules.World.Permissions permission = false; } + // Group members should be able to edit group objects + if ( (group.GroupID != UUID.Zero) && ((m_scene.GetSceneObjectPart(objId).GroupMask & (uint)PermissionMask.Modify) != 0) && IsGroupMember(group.GroupID, currentUser, 0) ) + { + // Return immediately, so that the administrator can shares group objects + return true; + } + // Users should be able to edit what is over their land. ILandObject parcel = m_scene.LandChannel.GetLandObject(group.AbsolutePosition.X, group.AbsolutePosition.Y); if ((parcel != null) && (parcel.landData.OwnerID == currentUser)) @@ -673,7 +722,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return permission; } - protected bool GenericParcelPermission(UUID user, ILandObject parcel) + protected bool GenericParcelPermission(UUID user, ILandObject parcel, ulong groupPowers) { bool permission = false; @@ -682,9 +731,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions permission = true; } - if (parcel.landData.IsGroupOwned) + if( ( parcel.landData.GroupID != UUID.Zero) && IsGroupMember(parcel.landData.GroupID, user, groupPowers) ) { - // TODO: Need to do some extra checks here. Requires group code. + permission = true; } if (IsEstateManager(user)) @@ -699,12 +748,39 @@ namespace OpenSim.Region.CoreModules.World.Permissions return permission; } + + protected bool GenericParcelOwnerPermission(UUID user, ILandObject parcel, ulong groupPowers) + { + bool permission = false; - protected bool GenericParcelPermission(UUID user, Vector3 pos) + if (parcel.landData.OwnerID == user) + { + permission = true; + } + + if( parcel.landData.IsGroupOwned && IsGroupMember(parcel.landData.GroupID, user, groupPowers) ) + { + permission = true; + } + + if (IsEstateManager(user)) + { + permission = true; + } + + if (IsAdministrator(user)) + { + permission = true; + } + + return permission; + } + + protected bool GenericParcelPermission(UUID user, Vector3 pos, ulong groupPowers) { ILandObject parcel = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); if (parcel == null) return false; - return GenericParcelPermission(user, parcel); + return GenericParcelPermission(user, parcel, groupPowers); } #endregion @@ -713,8 +789,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions { DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - - return GenericParcelPermission(user, parcel); + + return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandRelease); } private bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene) @@ -722,7 +798,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericParcelPermission(user, parcel); + return GenericParcelOwnerPermission(user, parcel, 0); } private bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene) @@ -736,10 +812,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions ScenePresence sp = scene.GetScenePresence(user); IClientAPI client = sp.ControllingClient; - if ((client.GetGroupPowers(parcel.landData.GroupID) & (long)GroupPowers.LandDeed) == 0) + if ((client.GetGroupPowers(parcel.landData.GroupID) & (ulong)GroupPowers.LandDeed) == 0) return false; - return GenericParcelPermission(user, parcel); + return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDeed); } private bool IsGod(UUID user, Scene scene) @@ -760,17 +836,23 @@ namespace OpenSim.Region.CoreModules.World.Permissions //They can't even edit the object return false; } - + SceneObjectPart part = scene.GetSceneObjectPart(objectID); if (part == null) return false; - if ((part.OwnerMask & PERM_COPY) == 0) - return false; + if (part.OwnerID == owner) + return ((part.OwnerMask & PERM_COPY) != 0); - if ((part.ParentGroup.GetEffectivePermissions() & PERM_COPY) == 0) - return false; + if (part.GroupID != UUID.Zero) + { + if ((part.OwnerID == UUID.Zero) && ((owner != part.LastOwnerID) || ((part.GroupMask & PERM_TRANS) == 0))) + return false; + if ((part.GroupMask & PERM_COPY) == 0) + return false; + } + //If they can rez, they can duplicate return CanRezObject(objectCount, owner, objectPosition, scene); } @@ -807,11 +889,6 @@ namespace OpenSim.Region.CoreModules.World.Permissions part = m_scene.GetSceneObjectPart(objectID); } - // TODO: add group support! - // - if (part.OwnerID != editorID) - return false; - return GenericObjectPermission(editorID, objectID, false); } @@ -820,7 +897,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericParcelPermission(user, parcel); + return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandDivideJoin); } /// @@ -901,10 +978,19 @@ namespace OpenSim.Region.CoreModules.World.Permissions return false; if (part.OwnerID != user) - return false; + { + if (part.GroupID == UUID.Zero) + return false; - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) + if( !IsGroupMember(part.GroupID, user, 0) ) + return false; + + if ((part.GroupMask & (uint)PermissionMask.Modify) == 0) + return false; + } else { + if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) return false; + } TaskInventoryItem ti = part.Inventory.GetInventoryItem(notecard); @@ -912,7 +998,13 @@ namespace OpenSim.Region.CoreModules.World.Permissions return false; if (ti.OwnerID != user) + { + if (ti.GroupID == UUID.Zero) + return false; + + if( !IsGroupMember(ti.GroupID, user, 0) ) return false; + } // Require full perms if ((ti.CurrentPermissions & @@ -1084,8 +1176,6 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; } - //TODO: check for group rights - if (!m_scene.Entities.ContainsKey(objectID)) { return false; @@ -1098,7 +1188,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions } - if (GenericParcelPermission(task.OwnerID, newPoint)) + if (GenericParcelPermission(task.OwnerID, newPoint, 0)) { return true; } @@ -1129,14 +1219,13 @@ namespace OpenSim.Region.CoreModules.World.Permissions (int)Parcel.ParcelFlags.CreateObjects) permission = true; - //TODO: check for group rights - if (IsAdministrator(owner)) { permission = true; } - if (GenericParcelPermission(owner, objectPosition)) + // Powers are zero, because GroupPowers.AllowRez is not a precondition for rezzing objects + if (GenericParcelPermission(owner, objectPosition, 0)) { permission = true; } @@ -1166,7 +1255,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - return GenericParcelPermission(user, parcel); + return GenericParcelOwnerPermission(user, parcel, (ulong)GroupPowers.LandSetSale); } private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) @@ -1182,7 +1271,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); if (m_bypassPermissions) return m_bypassPermissionsValue; - bool permission = GenericObjectPermission(userID, objectID,false); + bool permission = GenericObjectPermission(userID, objectID, false); if (!permission) { if (!m_scene.Entities.ContainsKey(objectID)) @@ -1249,7 +1338,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; // Land owner can terraform too - if (parcel != null && GenericParcelPermission(user, parcel)) + if (parcel != null && GenericParcelPermission(user, parcel, (ulong)GroupPowers.AllowEditLand)) return true; return false; @@ -1316,20 +1405,35 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (part == null) return false; - + if (part.OwnerID != user) + { + if (part.GroupID == UUID.Zero) return false; - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) - return false; + if( !IsGroupMember(part.GroupID, user, 0) ) + return false; + + if ((part.GroupMask & (uint)PermissionMask.Modify) == 0) + return false; + } else { + if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) + return false; + } TaskInventoryItem ti = part.Inventory.GetInventoryItem(script); if (ti == null) return false; - + if (ti.OwnerID != user) - return false; + { + if (ti.GroupID == UUID.Zero) + return false; + + if( !IsGroupMember(ti.GroupID, user, 0) ) + return false; + } // Require full perms if ((ti.CurrentPermissions & @@ -1394,9 +1498,15 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (part == null) return false; - + if (part.OwnerID != user) - return false; + { + if (part.GroupID == UUID.Zero) + return false; + + if( !IsGroupMember(part.GroupID, user, 0) ) + return false; + } if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) return false; @@ -1407,7 +1517,13 @@ namespace OpenSim.Region.CoreModules.World.Permissions return false; if (ti.OwnerID != user) - return false; + { + if (ti.GroupID == UUID.Zero) + return false; + + if( !IsGroupMember(ti.GroupID, user, 0) ) + return false; + } // Notecards are always readable unless no copy // @@ -1420,7 +1536,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; } - #endregion + #endregion private bool CanLinkObject(UUID userID, UUID objectID) { @@ -1589,7 +1705,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (parcel.landData.OwnerID != client.AgentId) return false; } - break; + return GenericParcelOwnerPermission(client.AgentId, parcel, (ulong)GroupPowers.ReturnGroupOwned); case (uint)ObjectReturnType.Group: if (parcel.landData.OwnerID != client.AgentId) { @@ -1613,45 +1729,44 @@ namespace OpenSim.Region.CoreModules.World.Permissions return true; } } - break; + return GenericParcelOwnerPermission(client.AgentId, parcel, (ulong)GroupPowers.ReturnGroupSet); case (uint)ObjectReturnType.Other: if ((powers & (long)GroupPowers.ReturnNonGroup) != 0) return true; - break; + return GenericParcelOwnerPermission(client.AgentId, parcel, (ulong)GroupPowers.ReturnNonGroup); case (uint)ObjectReturnType.List: break; } - return GenericParcelPermission(client.AgentId, parcel); + return GenericParcelOwnerPermission(client.AgentId, parcel, 0); + // Is it correct to be less restrictive for lists of objects to be returned? } private bool CanCompileScript(UUID ownerUUID, int scriptType, Scene scene) { - //m_log.DebugFormat("check if {0} is allowed to compile {1}", ownerUUID, scriptType); - switch(scriptType) { - case 0: - if(GrantLSL.Count == 0 || GrantLSL.ContainsKey(ownerUUID.ToString())) { - return(true); - } - break; - case 1: - if(GrantCS.Count == 0 || GrantCS.ContainsKey(ownerUUID.ToString())) { - return(true); - } - break; - case 2: - if(GrantVB.Count == 0 || GrantVB.ContainsKey(ownerUUID.ToString())) { - return(true); - } - break; - case 3: - if(GrantJS.Count == 0 || GrantJS.ContainsKey(ownerUUID.ToString())) { - return(true); - } - break; - } - return(false); - } - - + //m_log.DebugFormat("check if {0} is allowed to compile {1}", ownerUUID, scriptType); + switch(scriptType) { + case 0: + if(GrantLSL.Count == 0 || GrantLSL.ContainsKey(ownerUUID.ToString())) { + return(true); + } + break; + case 1: + if(GrantCS.Count == 0 || GrantCS.ContainsKey(ownerUUID.ToString())) { + return(true); + } + break; + case 2: + if(GrantVB.Count == 0 || GrantVB.ContainsKey(ownerUUID.ToString())) { + return(true); + } + break; + case 3: + if(GrantJS.Count == 0 || GrantJS.ContainsKey(ownerUUID.ToString())) { + return(true); + } + break; + } + return(false); + } } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 6efcaa7e8c..a2a7392f3c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1526,10 +1526,14 @@ namespace OpenSim.Region.Framework.Scenes return; if (part.OwnerID != remoteClient.AgentId) - return; - - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) - return; + { + // Group permissions + if ( (part.GroupID == UUID.Zero) || (remoteClient.GetGroupPowers(part.GroupID) == 0) || ((part.GroupMask & (uint)PermissionMask.Modify) == 0) ) + return; + } else { + if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) + return; + } if (!Permissions.CanCreateObjectInventory( itemBase.InvType, part.UUID, remoteClient.AgentId)) @@ -1598,13 +1602,18 @@ namespace OpenSim.Region.Framework.Scenes destId); return; } - + // Must own the object, and have modify rights if (srcPart.OwnerID != destPart.OwnerID) - return; - - if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0) - return; + { + // Group permissions + if ( (destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) || + ((destPart.GroupMask & (uint)PermissionMask.Modify) == 0) ) + return; + } else { + if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0) + return; + } if (destPart.ScriptAccessPin != pin) {