From 344c9caeb671f3d9dab80f05d18a7dc9f3075bc1 Mon Sep 17 00:00:00 2001 From: Johan Berntsson Date: Wed, 23 Jul 2008 06:59:02 +0000 Subject: thanks lulurun for a security patch that blocks unathorized access to the inventory server (see http://opensimulator.org/wiki/Security_vulnerability_brought_by_non-check_inventory_service) --- .../Communications/Cache/CachedUserInfo.cs | 24 +++++++++---- .../Cache/UserProfileCacheService.cs | 29 ++++++++++++++- .../Communications/CommunicationsManager.cs | 6 ++++ .../Grid/InventoryServer/GridInventoryService.cs | 41 ++++++++++++++++++++++ OpenSim/Grid/InventoryServer/Main.cs | 39 ++++++++++---------- OpenSim/Grid/UserServer/Main.cs | 1 + OpenSim/Grid/UserServer/UserManager.cs | 39 ++++++++++++++++++++ .../Communications/OGS1/CommunicationsOGS1.cs | 1 + OpenSim/Region/Environment/Scenes/Scene.cs | 3 +- prebuild.xml | 1 + 10 files changed, 156 insertions(+), 28 deletions(-) diff --git a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs index 4e57ead..c125976 100644 --- a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs +++ b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs @@ -87,6 +87,9 @@ namespace OpenSim.Framework.Communications.Cache private IDictionary> pendingCategorizationFolders = new Dictionary>(); + private LLUUID m_session_id = LLUUID.Zero; + public LLUUID SessionID { get { return m_session_id; } } + /// /// Constructor /// @@ -98,6 +101,13 @@ namespace OpenSim.Framework.Communications.Cache m_userProfile = userProfile; } + public CachedUserInfo(CommunicationsManager commsManager, UserProfileData userProfile, IClientAPI remoteClient) + { + m_commsManager = commsManager; + m_userProfile = userProfile; + m_session_id = remoteClient.SessionId; + } + /// /// This allows a request to be added to be processed once we receive a user's inventory /// from the inventory service. If we already have the inventory, the request @@ -325,7 +335,7 @@ namespace OpenSim.Framework.Communications.Cache createdBaseFolder.Type = createdFolder.Type; createdBaseFolder.Version = createdFolder.Version; - m_commsManager.InventoryService.AddFolder(createdBaseFolder); + m_commsManager.SecureInventoryService.AddFolder(createdBaseFolder, m_session_id); return true; } @@ -379,7 +389,7 @@ namespace OpenSim.Framework.Communications.Cache baseFolder.Type = (short)type; baseFolder.Version = RootFolder.Version; - m_commsManager.InventoryService.UpdateFolder(baseFolder); + m_commsManager.SecureInventoryService.UpdateFolder(baseFolder, m_session_id); InventoryFolderImpl folder = RootFolder.FindFolder(folderID); if (folder != null) @@ -421,7 +431,7 @@ namespace OpenSim.Framework.Communications.Cache baseFolder.ID = folderID; baseFolder.ParentID = parentID; - m_commsManager.InventoryService.MoveFolder(baseFolder); + m_commsManager.SecureInventoryService.MoveFolder(baseFolder, m_session_id); InventoryFolderImpl folder = RootFolder.FindFolder(folderID); if (folder != null) @@ -468,7 +478,7 @@ namespace OpenSim.Framework.Communications.Cache purgedBaseFolder.Type = purgedFolder.Type; purgedBaseFolder.Version = purgedFolder.Version; - m_commsManager.InventoryService.PurgeFolder(purgedBaseFolder); + m_commsManager.SecureInventoryService.PurgeFolder(purgedBaseFolder, m_session_id); purgedFolder.Purge(); @@ -505,7 +515,7 @@ namespace OpenSim.Framework.Communications.Cache item.Folder = RootFolder.ID; } ItemReceive(item); - m_commsManager.InventoryService.AddItem(item); + m_commsManager.SecureInventoryService.AddItem(item, m_session_id); } else { @@ -525,7 +535,7 @@ namespace OpenSim.Framework.Communications.Cache { if (HasInventory) { - m_commsManager.InventoryService.UpdateItem(item); + m_commsManager.SecureInventoryService.UpdateItem(item, m_session_id); } else { @@ -564,7 +574,7 @@ namespace OpenSim.Framework.Communications.Cache if (RootFolder.DeleteItem(item.ID)) { - return m_commsManager.InventoryService.DeleteItem(item); + return m_commsManager.SecureInventoryService.DeleteItem(item, m_session_id); } } else diff --git a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs index 0040718..e22dff6 100644 --- a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs +++ b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs @@ -63,6 +63,33 @@ namespace OpenSim.Framework.Communications.Cache /// A new user has moved into a region in this instance so retrieve their profile from the user service. /// /// + public void AddNewUser(IClientAPI remoteClient) + { + // Potential fix - Multithreading issue. + lock (m_userProfiles) + { + if (!m_userProfiles.ContainsKey(remoteClient.AgentId)) + { + UserProfileData userProfile = m_commsManager.UserService.GetUserProfile(remoteClient.AgentId); + CachedUserInfo userInfo = new CachedUserInfo(m_commsManager, userProfile, remoteClient); + + if (userInfo.UserProfile != null) + { + // The inventory for the user will be populated when they actually enter the scene + m_userProfiles.Add(remoteClient.AgentId, userInfo); + } + else + { + m_log.ErrorFormat("[USER CACHE]: User profile for user {0} not found.", remoteClient.AgentId); + } + } + } + } + + /// + /// A new user has moved into a region in this instance so retrieve their profile from the user service. + /// + /// public void AddNewUser(LLUUID userID) { // Potential fix - Multithreading issue. @@ -119,7 +146,7 @@ namespace OpenSim.Framework.Communications.Cache CachedUserInfo userInfo = GetUserDetails(userID); if (userInfo != null) { - m_commsManager.InventoryService.RequestInventoryForUser(userID, userInfo.InventoryReceive); + m_commsManager.SecureInventoryService.RequestInventoryForUser(userID, userInfo.SessionID, userInfo.InventoryReceive); //IInventoryServices invService = userInfo.GetInventoryService(); //if (invService != null) //{ diff --git a/OpenSim/Framework/Communications/CommunicationsManager.cs b/OpenSim/Framework/Communications/CommunicationsManager.cs index 5be7334..8caeeb3 100644 --- a/OpenSim/Framework/Communications/CommunicationsManager.cs +++ b/OpenSim/Framework/Communications/CommunicationsManager.cs @@ -112,7 +112,13 @@ namespace OpenSim.Framework.Communications protected List m_inventoryServices = new List(); // protected IInventoryServices m_inventoryService; + protected ISecureInventoryService m_secureinventoryServices; + public ISecureInventoryService SecureInventoryService + { + get { return m_secureinventoryServices; } + } + public IInventoryServices InventoryService { get diff --git a/OpenSim/Grid/InventoryServer/GridInventoryService.cs b/OpenSim/Grid/InventoryServer/GridInventoryService.cs index 5388263..78f33a3 100644 --- a/OpenSim/Grid/InventoryServer/GridInventoryService.cs +++ b/OpenSim/Grid/InventoryServer/GridInventoryService.cs @@ -26,12 +26,15 @@ */ using System; +using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Threading; +using System.Net; using libsecondlife; using log4net; +using Nwc.XmlRpc; using OpenSim.Framework; using OpenSim.Framework.Communications; @@ -46,6 +49,44 @@ namespace OpenSim.Grid.InventoryServer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string m_userserver_url; + + public GridInventoryService(string userserver_url) + { + m_userserver_url = userserver_url; + } + + public bool CheckTrustSource(IPEndPoint peer) + { + m_log.InfoFormat("[GRID AGENT INVENTORY]: checking trusted source {0}", peer.ToString()); + UriBuilder ub = new UriBuilder(m_userserver_url); + if (ub.Host == peer.Address.ToString()) + { + return true; + } + return false; + } + + public bool CheckAuthSession(string session_id, string avatar_id) + { + m_log.InfoFormat("[GRID AGENT INVENTORY]: checking authed session {0} {1}", session_id, avatar_id); + Hashtable requestData = new Hashtable(); + requestData["avatar_uuid"] = avatar_id; + requestData["session_id"] = session_id; + ArrayList SendParams = new ArrayList(); + SendParams.Add(requestData); + XmlRpcRequest UserReq = new XmlRpcRequest("check_auth_session", SendParams); + XmlRpcResponse UserResp = UserReq.Send(m_userserver_url, 3000); + + Hashtable responseData = (Hashtable)UserResp.Value; + + if (responseData.ContainsKey("auth_session") && responseData["auth_session"].ToString() == "TRUE") + { + return true; + } + return false; + } + public override void RequestInventoryForUser(LLUUID userID, InventoryReceiptCallback callback) { } diff --git a/OpenSim/Grid/InventoryServer/Main.cs b/OpenSim/Grid/InventoryServer/Main.cs index 2ab1916..138aa1a 100644 --- a/OpenSim/Grid/InventoryServer/Main.cs +++ b/OpenSim/Grid/InventoryServer/Main.cs @@ -70,7 +70,8 @@ namespace OpenSim.Grid.InventoryServer m_config = new InventoryConfig(LogName, (Path.Combine(Util.configDir(), "InventoryServer_Config.xml"))); - m_inventoryService = new GridInventoryService(); + //m_inventoryService = new GridInventoryService(); + m_inventoryService = new GridInventoryService(m_config.UserServerURL); m_inventoryService.AddPlugin(m_config.DatabaseProvider, m_config.DatabaseConnect); m_log.Info("[" + LogName + "]: Starting HTTP server ..."); @@ -85,36 +86,36 @@ namespace OpenSim.Grid.InventoryServer protected void AddHttpHandlers() { m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/GetInventory/", m_inventoryService.GetUserInventory)); + new RestDeserialiseSecureHandler( + "POST", "/GetInventory/", m_inventoryService.GetUserInventory, m_inventoryService.CheckAuthSession)); m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/CreateInventory/", m_inventoryService.CreateUsersInventory)); + new RestDeserialiseTrustedHandler( + "POST", "/CreateInventory/", m_inventoryService.CreateUsersInventory, m_inventoryService.CheckTrustSource)); m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/NewFolder/", m_inventoryService.AddFolder)); + new RestDeserialiseSecureHandler( + "POST", "/NewFolder/", m_inventoryService.AddFolder, m_inventoryService.CheckAuthSession)); m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/UpdateFolder/", m_inventoryService.UpdateFolder)); + new RestDeserialiseSecureHandler( + "POST", "/UpdateFolder/", m_inventoryService.UpdateFolder, m_inventoryService.CheckAuthSession)); m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/MoveFolder/", m_inventoryService.MoveFolder)); + new RestDeserialiseSecureHandler( + "POST", "/MoveFolder/", m_inventoryService.MoveFolder, m_inventoryService.CheckAuthSession)); m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/PurgeFolder/", m_inventoryService.PurgeFolder)); + new RestDeserialiseSecureHandler( + "POST", "/PurgeFolder/", m_inventoryService.PurgeFolder, m_inventoryService.CheckAuthSession)); m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/NewItem/", m_inventoryService.AddItem)); + new RestDeserialiseSecureHandler( + "POST", "/NewItem/", m_inventoryService.AddItem, m_inventoryService.CheckAuthSession)); m_httpServer.AddStreamHandler( - new RestDeserialiseHandler( - "POST", "/DeleteItem/", m_inventoryService.DeleteItem)); + new RestDeserialiseSecureHandler( + "POST", "/DeleteItem/", m_inventoryService.DeleteItem, m_inventoryService.CheckAuthSession)); // WARNING: Root folders no longer just delivers the root and immediate child folders (e.g // system folders such as Objects, Textures), but it now returns the entire inventory skeleton. @@ -122,8 +123,8 @@ namespace OpenSim.Grid.InventoryServer // (e.g. any http request not found is automatically treated as an xmlrpc request) make it easier // to do this for now. m_httpServer.AddStreamHandler( - new RestDeserialiseHandler> - ("POST", "/RootFolders/", m_inventoryService.GetInventorySkeleton)); + new RestDeserialiseTrustedHandler> + ("POST", "/RootFolders/", m_inventoryService.GetInventorySkeleton, m_inventoryService.CheckTrustSource)); } private void Work() diff --git a/OpenSim/Grid/UserServer/Main.cs b/OpenSim/Grid/UserServer/Main.cs index c7011a9..30a41f4 100644 --- a/OpenSim/Grid/UserServer/Main.cs +++ b/OpenSim/Grid/UserServer/Main.cs @@ -142,6 +142,7 @@ namespace OpenSim.Grid.UserServer m_httpServer.AddXmlRPCHandler("update_user_current_region", m_userManager.XmlRPCAtRegion); m_httpServer.AddXmlRPCHandler("logout_of_simulator", m_userManager.XmlRPCLogOffUserMethodUUID); m_httpServer.AddXmlRPCHandler("get_agent_by_uuid", m_userManager.XmlRPCGetAgentMethodUUID); + m_httpServer.AddXmlRPCHandler("check_auth_session", m_userManager.XmlRPCCheckAuthSession); // Message Server ---> User Server m_httpServer.AddXmlRPCHandler("register_messageserver", m_messagesService.XmlRPCRegisterMessageServer); m_httpServer.AddXmlRPCHandler("agent_change_region", m_messagesService.XmlRPCUserMovedtoRegion); diff --git a/OpenSim/Grid/UserServer/UserManager.cs b/OpenSim/Grid/UserServer/UserManager.cs index ff62d78..a43ade1 100644 --- a/OpenSim/Grid/UserServer/UserManager.cs +++ b/OpenSim/Grid/UserServer/UserManager.cs @@ -457,6 +457,45 @@ namespace OpenSim.Grid.UserServer return response; } + public XmlRpcResponse XmlRPCCheckAuthSession(XmlRpcRequest request) + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable requestData = (Hashtable)request.Params[0]; + UserProfileData userProfile; + + string authed = "FALSE"; + if (requestData.Contains("avatar_uuid") && requestData.Contains("session_id")) + { + LLUUID guess_aid = LLUUID.Zero; + LLUUID guess_sid = LLUUID.Zero; + + Helpers.TryParse((string)requestData["avatar_uuid"], out guess_aid); + if (guess_aid == LLUUID.Zero) + { + return CreateUnknownUserErrorResponse(); + } + Helpers.TryParse((string)requestData["session_id"], out guess_sid); + if (guess_sid == LLUUID.Zero) + { + return CreateUnknownUserErrorResponse(); + } + userProfile = GetUserProfile(guess_aid); + if (userProfile != null && userProfile.CurrentAgent != null && userProfile.CurrentAgent.SessionID == guess_sid) + { + authed = "TRUE"; + } + m_log.InfoFormat("[UserManager]: CheckAuthSession TRUE for user {0}", guess_aid); + } + else + { + m_log.InfoFormat("[UserManager]: CheckAuthSession FALSE"); + return CreateUnknownUserErrorResponse(); + } + Hashtable responseData = new Hashtable(); + responseData["auth_session"] = authed; + response.Value = responseData; + return response; + } public XmlRpcResponse XmlRpcResponseXmlRPCUpdateUserProfile(XmlRpcRequest request) { diff --git a/OpenSim/Region/Communications/OGS1/CommunicationsOGS1.cs b/OpenSim/Region/Communications/OGS1/CommunicationsOGS1.cs index f2e76f2..a6ea128 100644 --- a/OpenSim/Region/Communications/OGS1/CommunicationsOGS1.cs +++ b/OpenSim/Region/Communications/OGS1/CommunicationsOGS1.cs @@ -41,6 +41,7 @@ namespace OpenSim.Region.Communications.OGS1 m_gridService = gridInterComms; m_interRegion = gridInterComms; + m_secureinventoryServices = new OGS1SecureInventoryService(serversInfo.InventoryURL); OGS1InventoryService invService = new OGS1InventoryService(serversInfo.InventoryURL); AddInventoryService(invService); m_defaultInventoryHost = invService.Host; diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 6bf552c..ae5a3c7 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -2019,7 +2019,8 @@ namespace OpenSim.Region.Environment.Scenes { m_log.Info("[REGION]: Add New Scene Presence"); - CommsManager.UserProfileCacheService.AddNewUser(client.AgentId); + //CommsManager.UserProfileCacheService.AddNewUser(client.AgentId); + CommsManager.UserProfileCacheService.AddNewUser(client); CreateAndAddScenePresence(client, child); } diff --git a/prebuild.xml b/prebuild.xml index 8e211c0..044aa99 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1772,6 +1772,7 @@ + -- cgit v1.1