/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ using System; using System.Collections; using System.Collections.Generic; using System.Threading; using libsecondlife; using Nwc.XmlRpc; using OpenSim.Framework.Communications.Cache; using OpenSim.Framework.Console; namespace OpenSim.Framework.UserManagement { public class LoginService { protected string m_welcomeMessage = "Welcome to OpenSim"; protected UserManagerBase m_userManager = null; protected Mutex m_loginMutex = new Mutex(false); /// /// Used during login to send the skeleton of the OpenSim Library to the client. /// protected LibraryRootFolder m_libraryRootFolder; public LoginService( UserManagerBase userManager, LibraryRootFolder libraryRootFolder, string welcomeMess) { m_userManager = userManager; m_libraryRootFolder = libraryRootFolder; if (welcomeMess != "") { m_welcomeMessage = welcomeMess; } } /// /// Main user login function /// /// The XMLRPC request /// The response to send public XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request) { // Temporary fix m_loginMutex.WaitOne(); try { //CFK: CustomizeResponse contains sufficient strings to alleviate the need for this. //CKF: MainLog.Instance.Verbose("LOGIN", "Attempting login now..."); XmlRpcResponse response = new XmlRpcResponse(); Hashtable requestData = (Hashtable) request.Params[0]; bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && requestData.Contains("passwd")); bool GoodLogin = false; UserProfileData userProfile; LoginResponse logResponse = new LoginResponse(); if (GoodXML) { string firstname = (string) requestData["first"]; string lastname = (string) requestData["last"]; string passwd = (string) requestData["passwd"]; userProfile = GetTheUser(firstname, lastname); if (userProfile == null) { MainLog.Instance.Verbose( "LOGIN", "Could not find a profile for " + firstname + " " + lastname); return logResponse.CreateLoginFailedResponse(); } GoodLogin = AuthenticateUser(userProfile, passwd); } else { return logResponse.CreateGridErrorResponse(); } if (!GoodLogin) { return logResponse.CreateLoginFailedResponse(); } else { // If we already have a session... if (userProfile.currentAgent != null && userProfile.currentAgent.agentOnline) { userProfile.currentAgent = null; m_userManager.CommitAgent(ref userProfile); // Reject the login return logResponse.CreateAlreadyLoggedInResponse(); } // Otherwise... // Create a new agent session CreateAgent(userProfile, request); try { LLUUID agentID = userProfile.UUID; // Inventory Library Section InventoryData inventData = CreateInventoryData(agentID); ArrayList AgentInventoryArray = inventData.InventoryArray; Hashtable InventoryRootHash = new Hashtable(); InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); ArrayList InventoryRoot = new ArrayList(); InventoryRoot.Add(InventoryRootHash); userProfile.rootInventoryFolderID = inventData.RootFolderID; // Circuit Code uint circode = (uint) (Util.RandomClass.Next()); logResponse.Lastname = userProfile.surname; logResponse.Firstname = userProfile.username; logResponse.AgentID = agentID.ToString(); logResponse.SessionID = userProfile.currentAgent.sessionID.ToString(); logResponse.SecureSessionID = userProfile.currentAgent.secureSessionID.ToString(); logResponse.InventoryRoot = InventoryRoot; logResponse.InventorySkeleton = AgentInventoryArray; logResponse.InventoryLibrary = GetInventoryLibrary(); Hashtable InventoryLibRootHash = new Hashtable(); InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; ArrayList InventoryLibRoot = new ArrayList(); InventoryLibRoot.Add(InventoryLibRootHash); logResponse.InventoryLibRoot = InventoryLibRoot; logResponse.InventoryLibraryOwner = GetLibraryOwner(); logResponse.CircuitCode = (Int32) circode; //logResponse.RegionX = 0; //overwritten //logResponse.RegionY = 0; //overwritten logResponse.Home = "!!null temporary value {home}!!"; // Overwritten //logResponse.LookAt = "\n[r" + TheUser.homeLookAt.X.ToString() + ",r" + TheUser.homeLookAt.Y.ToString() + ",r" + TheUser.homeLookAt.Z.ToString() + "]\n"; //logResponse.SimAddress = "127.0.0.1"; //overwritten //logResponse.SimPort = 0; //overwritten logResponse.Message = GetMessage(); logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); try { CustomiseResponse(logResponse, userProfile); } catch (Exception e) { MainLog.Instance.Verbose("LOGIN", e.ToString()); return logResponse.CreateDeadRegionResponse(); //return logResponse.ToXmlRpcResponse(); } CommitAgent(ref userProfile); return logResponse.ToXmlRpcResponse(); } catch (Exception E) { MainLog.Instance.Verbose("LOGIN", E.ToString()); } //} } return response; } finally { m_loginMutex.ReleaseMutex(); } } /// /// Customises the login response and fills in missing values. /// /// The existing response /// The user profile public virtual void CustomiseResponse(LoginResponse response, UserProfileData theUser) { } /// /// Saves a target agent to the database /// /// The users profile /// Successful? public bool CommitAgent(ref UserProfileData profile) { return m_userManager.CommitAgent(ref profile); } /// /// Checks a user against it's password hash /// /// The users profile /// The supplied password /// Authenticated? public virtual bool AuthenticateUser(UserProfileData profile, string password) { MainLog.Instance.Verbose( "LOGIN", "Authenticating {0} {1} ({2})", profile.username, profile.surname, profile.UUID); password = password.Remove(0, 3); //remove $1$ string s = Util.Md5Hash(password + ":" + profile.passwordSalt); return profile.passwordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase); } /// /// /// /// /// public void CreateAgent(UserProfileData profile, XmlRpcRequest request) { m_userManager.CreateAgent(profile, request); } /// /// /// /// /// /// public virtual UserProfileData GetTheUser(string firstname, string lastname) { return m_userManager.GetUserProfile(firstname, lastname); } /// /// /// /// public virtual string GetMessage() { return m_welcomeMessage; } private LoginResponse.BuddyList ConvertFriendListItem(List LFL) { LoginResponse.BuddyList buddylistreturn = new LoginResponse.BuddyList(); foreach (FriendListItem fl in LFL) { LoginResponse.BuddyList.BuddyInfo buddyitem = new LoginResponse.BuddyList.BuddyInfo(fl.Friend); buddyitem.BuddyID = fl.Friend; buddyitem.BuddyRightsHave = (int)fl.FriendListOwnerPerms; buddyitem.BuddyRightsGiven = (int) fl.FriendPerms; buddylistreturn.AddNewBuddy(buddyitem); } return buddylistreturn; } /// /// Converts the inventory library skeleton into the form required by the rpc request. /// /// protected virtual ArrayList GetInventoryLibrary() { Dictionary rootFolders = m_libraryRootFolder.RequestSelfAndDescendentFolders(); ArrayList folderHashes = new ArrayList(); foreach (InventoryFolderBase folder in rootFolders.Values) { Hashtable TempHash = new Hashtable(); TempHash["name"] = folder.name; TempHash["parent_id"] = folder.parentID.ToString(); TempHash["version"] = (Int32)folder.version; TempHash["type_default"] = (Int32)folder.type; TempHash["folder_id"] = folder.folderID.ToString(); folderHashes.Add(TempHash); } return folderHashes; } /// /// /// /// protected virtual ArrayList GetLibraryOwner() { //for now create random inventory library owner Hashtable TempHash = new Hashtable(); TempHash["agent_id"] = "11111111-1111-0000-0000-000100bba000"; ArrayList inventoryLibOwner = new ArrayList(); inventoryLibOwner.Add(TempHash); return inventoryLibOwner; } protected virtual InventoryData CreateInventoryData(LLUUID userID) { AgentInventory userInventory = new AgentInventory(); userInventory.CreateRootFolder(userID, false); ArrayList AgentInventoryArray = new ArrayList(); Hashtable TempHash; foreach (InventoryFolder InvFolder in userInventory.InventoryFolders.Values) { TempHash = new Hashtable(); TempHash["name"] = InvFolder.FolderName; TempHash["parent_id"] = InvFolder.ParentID.ToString(); TempHash["version"] = (Int32) InvFolder.Version; TempHash["type_default"] = (Int32) InvFolder.DefaultType; TempHash["folder_id"] = InvFolder.FolderID.ToString(); AgentInventoryArray.Add(TempHash); } return new InventoryData(AgentInventoryArray, userInventory.InventoryRoot.FolderID); } public class InventoryData { public ArrayList InventoryArray = null; public LLUUID RootFolderID = LLUUID.Zero; public InventoryData(ArrayList invList, LLUUID rootID) { InventoryArray = invList; RootFolderID = rootID; } } } }