/// <summary> /// Called when we receive the client's initial XMLRPC login_to_simulator request message /// </summary> /// <param name="request">The XMLRPC request</param> /// <returns>The response to send</returns> public virtual XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request, IPEndPoint remoteClient) { // Temporary fix m_loginMutex.WaitOne(); try { //CFK: CustomizeResponse contains sufficient strings to alleviate the need for this. //CKF: m_log.Info("[LOGIN]: Attempting login now..."); XmlRpcResponse response = new XmlRpcResponse(); Hashtable requestData = (Hashtable)request.Params[0]; SniffLoginKey((Uri)request.Params[2], requestData); bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && (requestData.Contains("passwd") || requestData.Contains("web_login_key"))); string startLocationRequest = "last"; UserProfileData userProfile; LoginResponse logResponse = new LoginResponse(); string firstname; string lastname; if (GoodXML) { if (requestData.Contains("start")) { startLocationRequest = (string)requestData["start"]; } firstname = (string)requestData["first"]; lastname = (string)requestData["last"]; m_log.InfoFormat( "[LOGIN BEGIN]: XMLRPC Received login request message from user '{0}' '{1}'", firstname, lastname); string clientVersion = "Unknown"; if (requestData.Contains("version")) { clientVersion = (string)requestData["version"]; } m_log.DebugFormat( "[LOGIN]: XMLRPC Client is {0}, start location is {1}", clientVersion, startLocationRequest); if (!TryAuthenticateXmlRpcLogin(request, firstname, lastname, out userProfile)) { return logResponse.CreateLoginFailedResponse(); } } else { m_log.Info( "[LOGIN END]: XMLRPC login_to_simulator login message did not contain all the required data"); return logResponse.CreateGridErrorResponse(); } if (userProfile.GodLevel < m_minLoginLevel) { return logResponse.CreateLoginBlockedResponse(); } else { // If we already have a session... if (userProfile.CurrentAgent != null && userProfile.CurrentAgent.AgentOnline) { //TODO: The following statements can cause trouble: // If agentOnline could not turn from true back to false normally // because of some problem, for instance, the crashment of server or client, // the user cannot log in any longer. userProfile.CurrentAgent.AgentOnline = false; m_userManager.CommitAgent(ref userProfile); // try to tell the region that their user is dead. LogOffUser(userProfile, " XMLRPC You were logged off because you logged in from another location"); if (m_warn_already_logged) { // This is behavior for for grid, reject login m_log.InfoFormat( "[LOGIN END]: XMLRPC Notifying user {0} {1} that they are already logged in", firstname, lastname); return logResponse.CreateAlreadyLoggedInResponse(); } else { // This is behavior for standalone (silent logout of last hung session) m_log.InfoFormat( "[LOGIN]: XMLRPC User {0} {1} is already logged in, not notifying user, kicking old presence and starting new login.", firstname, lastname); } } // Otherwise... // Create a new agent session // XXYY we don't need this //m_userManager.ResetAttachments(userProfile.ID); CreateAgent(userProfile, request); // We need to commit the agent right here, even though the userProfile info is not complete // at this point. There is another commit further down. // This is for the new sessionID to be stored so that the region can check it for session authentication. // CustomiseResponse->PrepareLoginToRegion CommitAgent(ref userProfile); try { UUID agentID = userProfile.ID; InventoryData inventData = null; try { inventData = GetInventorySkeleton(agentID); } catch (Exception e) { m_log.ErrorFormat( "[LOGIN END]: Error retrieving inventory skeleton of agent {0} - {1}", agentID, e); // Let's not panic if (!AllowLoginWithoutInventory()) return logResponse.CreateLoginInventoryFailedResponse(); } if (inventData != null) { ArrayList AgentInventoryArray = inventData.InventoryArray; Hashtable InventoryRootHash = new Hashtable(); InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); ArrayList InventoryRoot = new ArrayList(); InventoryRoot.Add(InventoryRootHash); logResponse.InventoryRoot = InventoryRoot; logResponse.InventorySkeleton = AgentInventoryArray; } // Inventory Library Section 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.InventoryLibrary = GetInventoryLibrary(); logResponse.CircuitCode = Util.RandomClass.Next(); logResponse.Lastname = userProfile.SurName; logResponse.Firstname = userProfile.FirstName; logResponse.AgentID = agentID; logResponse.SessionID = userProfile.CurrentAgent.SessionID; logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID; logResponse.Message = GetMessage(); logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); logResponse.StartLocation = startLocationRequest; if (CustomiseResponse(logResponse, userProfile, startLocationRequest, remoteClient)) { userProfile.LastLogin = userProfile.CurrentAgent.LoginTime; CommitAgent(ref userProfile); // If we reach this point, then the login has successfully logged onto the grid if (StatsManager.UserStats != null) StatsManager.UserStats.AddSuccessfulLogin(); m_log.DebugFormat( "[LOGIN END]: XMLRPC Authentication of user {0} {1} successful. Sending response to client.", firstname, lastname); return logResponse.ToXmlRpcResponse(); } else { m_log.ErrorFormat("[LOGIN END]: XMLRPC informing user {0} {1} that login failed due to an unavailable region", firstname, lastname); return logResponse.CreateDeadRegionResponse(); } } catch (Exception e) { m_log.Error("[LOGIN END]: XMLRPC Login failed, " + e); m_log.Error(e.StackTrace); } } m_log.Info("[LOGIN END]: XMLRPC Login failed. Sending back blank XMLRPC response"); return response; } finally { m_loginMutex.ReleaseMutex(); } }
/// <summary> /// Called when we receive the client's initial XMLRPC login_to_simulator request message /// </summary> /// <param name="request">The XMLRPC request</param> /// <returns>The response to send</returns> public virtual XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request, IPEndPoint remoteClient) { string loginUsername = null; try { XmlRpcResponse response = new XmlRpcResponse(); Hashtable requestData = (Hashtable)request.Params[0]; SniffLoginKey((Uri)request.Params[2], requestData); bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && (requestData.Contains("passwd") || requestData.Contains("web_login_key"))); string firstname = null; string lastname = null; LoginResponse logResponse = new LoginResponse(); if (GoodXML) { //make sure the user isn't already trying to log in firstname = (string)requestData["first"]; lastname = (string)requestData["last"]; loginUsername = firstname + " " + lastname; lock (_loginsProcessing) { if (_loginsProcessing.Contains(loginUsername)) { return logResponse.CreateAlreadyLoggedInResponse(); } else { _loginsProcessing.Add(loginUsername); } } } string startLocationRequest = "last"; UserProfileData userProfile; string clientVersion = "Unknown"; if (GoodXML) { if (requestData.Contains("start")) { startLocationRequest = (string)requestData["start"]; } m_log.InfoFormat( "[LOGIN BEGIN]: XMLRPC Received login request message from user '{0}' '{1}'", firstname, lastname); if (requestData.Contains("version")) { clientVersion = (string)requestData["version"]; } if (this.IsViewerBlacklisted(clientVersion)) { m_log.DebugFormat("[LOGIN]: Denying login, Client {0} is blacklisted", clientVersion); return logResponse.CreateViewerNotAllowedResponse(); } m_log.DebugFormat( "[LOGIN]: XMLRPC Client is {0}, start location is {1}", clientVersion, startLocationRequest); if (!TryAuthenticateXmlRpcLogin(request, firstname, lastname, out userProfile)) { return logResponse.CreateLoginFailedResponse(); } } else { m_log.Info("[LOGIN END]: XMLRPC login_to_simulator login message did not contain all the required data"); return logResponse.CreateGridErrorResponse(); } if (userProfile.GodLevel < m_minLoginLevel) { return logResponse.CreateLoginBlockedResponse(); } else { // If we already have a session... if (userProfile.CurrentAgent != null && userProfile.CurrentAgent.AgentOnline) { // Force a refresh for this due to Commit below UUID userID = userProfile.ID; m_userManager.PurgeUserFromCaches(userID); userProfile = m_userManager.GetUserProfile(userID); // on an error, return the former error we returned before recovery was supported. if (userProfile == null) return logResponse.CreateAlreadyLoggedInResponse(); //TODO: The following statements can cause trouble: // If agentOnline could not turn from true back to false normally // because of some problem, for instance, the crashment of server or client, // the user cannot log in any longer. userProfile.CurrentAgent.AgentOnline = false; userProfile.CurrentAgent.LogoutTime = Util.UnixTimeSinceEpoch(); m_userManager.CommitAgent(ref userProfile); // try to tell the region that their user is dead. LogOffUser(userProfile, " XMLRPC You were logged off because you logged in from another location"); // Don't reject the login. We've already cleaned it up, above. m_log.InfoFormat( "[LOGIN END]: XMLRPC Reset user {0} {1} that we believe is already logged in", firstname, lastname); // return logResponse.CreateAlreadyLoggedInResponse(); } // Otherwise... // Create a new agent session m_userManager.ResetAttachments(userProfile.ID); CreateAgent(userProfile, request); // We need to commit the agent right here, even though the userProfile info is not complete // at this point. There is another commit further down. // This is for the new sessionID to be stored so that the region can check it for session authentication. // CustomiseResponse->PrepareLoginToRegion CommitAgent(ref userProfile); try { UUID agentID = userProfile.ID; InventoryData inventData = null; try { inventData = GetInventorySkeleton(agentID); } catch (Exception e) { m_log.ErrorFormat( "[LOGIN END]: Error retrieving inventory skeleton of agent {0} - {1}", agentID, e); return logResponse.CreateLoginInventoryFailedResponse(); } if (inventData != null) { 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; logResponse.InventoryRoot = InventoryRoot; logResponse.InventorySkeleton = AgentInventoryArray; } // Inventory Library Section 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.InventoryLibrary = GetInventoryLibrary(); logResponse.CircuitCode = Util.RandomClass.Next(); logResponse.Lastname = userProfile.SurName; logResponse.Firstname = userProfile.FirstName; logResponse.AgentID = agentID; logResponse.SessionID = userProfile.CurrentAgent.SessionID; logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID; logResponse.Message = GetMessage(); logResponse.MapServerURI = m_MapServerURI; logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); logResponse.StartLocation = startLocationRequest; // m_log.WarnFormat("[LOGIN END]: >>> Login response for {0} SSID={1}", logResponse.AgentID, logResponse.SecureSessionID); if (CustomiseResponse(logResponse, userProfile, startLocationRequest, clientVersion)) { userProfile.LastLogin = userProfile.CurrentAgent.LoginTime; CommitAgent(ref userProfile); // If we reach this point, then the login has successfully logged onto the grid if (StatsManager.UserStats != null) StatsManager.UserStats.AddSuccessfulLogin(); m_log.DebugFormat( "[LOGIN END]: XMLRPC Authentication of user {0} {1} successful. Sending response to client.", firstname, lastname); return logResponse.ToXmlRpcResponse(); } else { m_log.ErrorFormat("[LOGIN END]: XMLRPC informing user {0} {1} that login failed due to an unavailable region", firstname, lastname); return logResponse.CreateDeadRegionResponse(); } } catch (Exception e) { m_log.Error("[LOGIN END]: XMLRPC Login failed, " + e); m_log.Error(e.StackTrace); } } m_log.Info("[LOGIN END]: XMLRPC Login failed. Sending back blank XMLRPC response"); return response; } finally { if (loginUsername != null) { lock (_loginsProcessing) { _loginsProcessing.Remove(loginUsername); } } } }
XmlRpcResponse LoginHandler(XmlRpcRequest request, Uri requestUrl) { XmlRpcResponse response = new XmlRpcResponse(); Hashtable requestData = (Hashtable)request.Params[0]; IPEndPoint remoteClient = null; if (request.Params.Count > 1) remoteClient = request.Params[1] as IPEndPoint; UserProfileData userProfile; LoginResponse logResponse = new LoginResponse(); UUID sessionID; IsXmlRpcLogin(requestUrl, out sessionID); m_log.Info("[CABLE BEACH XMLRPC]: XML-RPC Received login request message with sessionID " + sessionID); string startLocationRequest = "last"; if (requestData.Contains("start")) startLocationRequest = (requestData["start"] as string) ?? "last"; string clientVersion = "Unknown"; if (requestData.Contains("version")) clientVersion = (requestData["version"] as string) ?? "Unknown"; if (TryAuthenticateXmlRpcLogin(sessionID, out userProfile)) { try { UUID agentID = userProfile.ID; LoginService.InventoryData skeleton = null; try { skeleton = CableBeachState.LoginService.GetInventorySkeleton(agentID); } catch (Exception e) { m_log.ErrorFormat("[CABLE BEACH XMLRPC]: Error retrieving inventory skeleton of agent {0} - {1}", agentID, e); // Let's not panic if (!CableBeachState.LoginService.AllowLoginWithoutInventory()) return logResponse.CreateLoginInventoryFailedResponse(); } #region Inventory Skeletons if (skeleton != null) { ArrayList AgentInventoryArray = skeleton.InventoryArray; Hashtable InventoryRootHash = new Hashtable(); InventoryRootHash["folder_id"] = skeleton.RootFolderID.ToString(); ArrayList InventoryRoot = new ArrayList(); InventoryRoot.Add(InventoryRootHash); logResponse.InventoryRoot = InventoryRoot; logResponse.InventorySkeleton = AgentInventoryArray; } // Inventory Library Section Hashtable InventoryLibRootHash = new Hashtable(); InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; ArrayList InventoryLibRoot = new ArrayList(); InventoryLibRoot.Add(InventoryLibRootHash); logResponse.InventoryLibRoot = InventoryLibRoot; logResponse.InventoryLibraryOwner = CableBeachState.LoginService.GetLibraryOwner(); logResponse.InventoryLibrary = CableBeachState.LoginService.GetInventoryLibrary(); logResponse.CircuitCode = Util.RandomClass.Next(); logResponse.Lastname = userProfile.SurName; logResponse.Firstname = userProfile.FirstName; logResponse.AgentID = agentID; logResponse.SessionID = userProfile.CurrentAgent.SessionID; logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID; logResponse.Message = CableBeachState.LoginService.GetMessage(); logResponse.BuddList = CableBeachState.LoginService.ConvertFriendListItem(CableBeachState.LoginService.UserManager.GetUserFriendList(agentID)); logResponse.StartLocation = startLocationRequest; #endregion Inventory Skeletons if (CableBeachState.LoginService.CustomiseResponse(logResponse, userProfile, startLocationRequest, remoteClient)) { userProfile.LastLogin = userProfile.CurrentAgent.LoginTime; CableBeachState.LoginService.CommitAgent(ref userProfile); // If we reach this point, then the login has successfully logged onto the grid if (StatsManager.UserStats != null) StatsManager.UserStats.AddSuccessfulLogin(); m_log.DebugFormat("[CABLE BEACH XMLRPC]: Authentication of user {0} {1} successful. Sending response to client", userProfile.FirstName, userProfile.FirstName); return logResponse.ToXmlRpcResponse(); } else { m_log.ErrorFormat("[CABLE BEACH XMLRPC]: Informing user {0} {1} that login failed due to an unavailable region", userProfile.FirstName, userProfile.FirstName); return logResponse.CreateDeadRegionResponse(); } } catch (Exception e) { m_log.Error("[CABLE BEACH XMLRPC]: Login failed, returning a blank response. Error: " + e); return response; } } else { m_log.Warn("[CABLE BEACH XMLRPC]: Authentication failed using sessionID " + sessionID + ", there are " + CableBeachState.PendingLogins.Count + " valid pending logins"); return logResponse.CreateLoginFailedResponse(); } }