aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Communications/Services
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Communications/Services')
-rw-r--r--OpenSim/Framework/Communications/Services/GridInfoService.cs176
-rw-r--r--OpenSim/Framework/Communications/Services/HGLoginAuthService.cs339
-rw-r--r--OpenSim/Framework/Communications/Services/LoginResponse.cs823
-rw-r--r--OpenSim/Framework/Communications/Services/LoginService.cs1241
4 files changed, 0 insertions, 2579 deletions
diff --git a/OpenSim/Framework/Communications/Services/GridInfoService.cs b/OpenSim/Framework/Communications/Services/GridInfoService.cs
deleted file mode 100644
index cd2a152..0000000
--- a/OpenSim/Framework/Communications/Services/GridInfoService.cs
+++ /dev/null
@@ -1,176 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using System.Text;
34using log4net;
35using Nini.Config;
36using Nwc.XmlRpc;
37using OpenSim.Framework.Servers.HttpServer;
38
39namespace OpenSim.Framework.Communications.Services
40{
41 public class GridInfoService
42 {
43 private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 private Hashtable _info = new Hashtable();
46
47 /// <summary>
48 /// Instantiate a GridInfoService object.
49 /// </summary>
50 /// <param name="configPath">path to config path containing
51 /// grid information</param>
52 /// <remarks>
53 /// GridInfoService uses the [GridInfo] section of the
54 /// standard OpenSim.ini file --- which is not optimal, but
55 /// anything else requires a general redesign of the config
56 /// system.
57 /// </remarks>
58 public GridInfoService(IConfigSource configSource)
59 {
60 loadGridInfo(configSource);
61 }
62
63 /// <summary>
64 /// Default constructor, uses OpenSim.ini.
65 /// </summary>
66 public GridInfoService()
67 {
68 try
69 {
70 IConfigSource configSource = new IniConfigSource(Path.Combine(Util.configDir(), "OpenSim.ini"));
71 loadGridInfo(configSource);
72 }
73 catch (FileNotFoundException)
74 {
75 _log.Warn(
76 "[GRID INFO SERVICE]: No OpenSim.ini file found --- GridInfoServices WILL NOT BE AVAILABLE to your users");
77 }
78 }
79
80 private void loadGridInfo(IConfigSource configSource)
81 {
82 _info["platform"] = "OpenSim";
83 try
84 {
85 IConfig startupCfg = configSource.Configs["Startup"];
86 IConfig gridCfg = configSource.Configs["GridInfo"];
87 IConfig netCfg = configSource.Configs["Network"];
88
89 bool grid = startupCfg.GetBoolean("gridmode", false);
90
91 if (grid)
92 _info["mode"] = "grid";
93 else
94 _info["mode"] = "standalone";
95
96
97 if (null != gridCfg)
98 {
99 foreach (string k in gridCfg.GetKeys())
100 {
101 _info[k] = gridCfg.GetString(k);
102 }
103 }
104 else if (null != netCfg)
105 {
106 if (grid)
107 _info["login"]
108 = netCfg.GetString(
109 "user_server_url", "http://127.0.0.1:" + ConfigSettings.DefaultUserServerHttpPort.ToString());
110 else
111 _info["login"]
112 = String.Format(
113 "http://127.0.0.1:{0}/",
114 netCfg.GetString(
115 "http_listener_port", ConfigSettings.DefaultRegionHttpPort.ToString()));
116
117 IssueWarning();
118 }
119 else
120 {
121 _info["login"] = "http://127.0.0.1:9000/";
122 IssueWarning();
123 }
124 }
125 catch (Exception)
126 {
127 _log.Debug("[GRID INFO SERVICE]: Cannot get grid info from config source, using minimal defaults");
128 }
129
130 _log.DebugFormat("[GRID INFO SERVICE]: Grid info service initialized with {0} keys", _info.Count);
131
132 }
133
134 private void IssueWarning()
135 {
136 _log.Warn("[GRID INFO SERVICE]: found no [GridInfo] section in your OpenSim.ini");
137 _log.Warn("[GRID INFO SERVICE]: trying to guess sensible defaults, you might want to provide better ones:");
138
139 foreach (string k in _info.Keys)
140 {
141 _log.WarnFormat("[GRID INFO SERVICE]: {0}: {1}", k, _info[k]);
142 }
143 }
144
145 public XmlRpcResponse XmlRpcGridInfoMethod(XmlRpcRequest request, IPEndPoint remoteClient)
146 {
147 XmlRpcResponse response = new XmlRpcResponse();
148 Hashtable responseData = new Hashtable();
149
150 _log.Info("[GRID INFO SERVICE]: Request for grid info");
151
152 foreach (string k in _info.Keys)
153 {
154 responseData[k] = _info[k];
155 }
156 response.Value = responseData;
157
158 return response;
159 }
160
161 public string RestGetGridInfoMethod(string request, string path, string param,
162 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
163 {
164 StringBuilder sb = new StringBuilder();
165
166 sb.Append("<gridinfo>\n");
167 foreach (string k in _info.Keys)
168 {
169 sb.AppendFormat("<{0}>{1}</{0}>\n", k, _info[k]);
170 }
171 sb.Append("</gridinfo>\n");
172
173 return sb.ToString();
174 }
175 }
176}
diff --git a/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs b/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs
deleted file mode 100644
index d3f813e..0000000
--- a/OpenSim/Framework/Communications/Services/HGLoginAuthService.cs
+++ /dev/null
@@ -1,339 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Text.RegularExpressions;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Framework.Capabilities;
37using OpenSim.Framework.Servers;
38
39using OpenMetaverse;
40
41using log4net;
42using Nini.Config;
43using Nwc.XmlRpc;
44
45namespace OpenSim.Framework.Communications.Services
46{
47 public class HGLoginAuthService : LoginService
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 protected NetworkServersInfo m_serversInfo;
52 protected bool m_authUsers = false;
53
54 /// <summary>
55 /// Used by the login service to make requests to the inventory service.
56 /// </summary>
57 protected IInterServiceInventoryServices m_interServiceInventoryService;
58
59 /// <summary>
60 /// Used to make requests to the local regions.
61 /// </summary>
62 protected ILoginServiceToRegionsConnector m_regionsConnector;
63
64 public HGLoginAuthService(
65 UserManagerBase userManager, string welcomeMess,
66 IInterServiceInventoryServices interServiceInventoryService,
67 NetworkServersInfo serversInfo,
68 bool authenticate, LibraryRootFolder libraryRootFolder, ILoginServiceToRegionsConnector regionsConnector)
69 : base(userManager, libraryRootFolder, welcomeMess)
70 {
71 this.m_serversInfo = serversInfo;
72 if (m_serversInfo != null)
73 {
74 m_defaultHomeX = this.m_serversInfo.DefaultHomeLocX;
75 m_defaultHomeY = this.m_serversInfo.DefaultHomeLocY;
76 }
77 m_authUsers = authenticate;
78
79 m_interServiceInventoryService = interServiceInventoryService;
80 m_regionsConnector = regionsConnector;
81 m_interInventoryService = interServiceInventoryService;
82 }
83
84 public void SetServersInfo(NetworkServersInfo sinfo)
85 {
86 m_serversInfo = sinfo;
87 }
88
89 public override XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request, IPEndPoint remoteClient)
90 {
91 m_log.Info("[HGLOGIN]: HGLogin called " + request.MethodName);
92 XmlRpcResponse response = base.XmlRpcLoginMethod(request, remoteClient);
93 Hashtable responseData = (Hashtable)response.Value;
94
95 responseData["grid_service"] = m_serversInfo.GridURL;
96 responseData["grid_service_send_key"] = m_serversInfo.GridSendKey;
97 responseData["inventory_service"] = m_serversInfo.InventoryURL;
98 responseData["asset_service"] = m_serversInfo.AssetURL;
99 responseData["asset_service_send_key"] = m_serversInfo.AssetSendKey;
100 int x = (Int32)responseData["region_x"];
101 int y = (Int32)responseData["region_y"];
102 uint ux = (uint)(x / Constants.RegionSize);
103 uint uy = (uint)(y / Constants.RegionSize);
104 ulong regionHandle = Util.UIntsToLong(ux, uy);
105 responseData["region_handle"] = regionHandle.ToString();
106
107 // Let's remove the seed cap from the login
108 //responseData.Remove("seed_capability");
109
110 // Let's add the appearance
111 UUID userID = UUID.Zero;
112 UUID.TryParse((string)responseData["agent_id"], out userID);
113 AvatarAppearance appearance = m_userManager.GetUserAppearance(userID);
114 if (appearance == null)
115 {
116 m_log.WarnFormat("[INTER]: Appearance not found for {0}. Creating default.", userID);
117 appearance = new AvatarAppearance();
118 }
119
120 responseData["appearance"] = appearance.ToHashTable();
121
122 // Let's also send the auth token
123 UUID token = UUID.Random();
124 responseData["auth_token"] = token.ToString();
125 UserProfileData userProfile = m_userManager.GetUserProfile(userID);
126 if (userProfile != null)
127 {
128 userProfile.WebLoginKey = token;
129 m_userManager.CommitAgent(ref userProfile);
130 }
131 m_log.Warn("[HGLOGIN]: Auth token: " + token);
132
133
134 return response;
135 }
136
137 public XmlRpcResponse XmlRpcGenerateKeyMethod(XmlRpcRequest request, IPEndPoint remoteClient)
138 {
139 // Verify the key of who's calling
140 UUID userID = UUID.Zero;
141 UUID authKey = UUID.Zero;
142 UUID.TryParse((string)request.Params[0], out userID);
143 UUID.TryParse((string)request.Params[1], out authKey);
144
145 m_log.InfoFormat("[HGLOGIN] HGGenerateKey called with authToken ", authKey);
146 string newKey = string.Empty;
147
148 if (!(m_userManager is IAuthentication))
149 {
150 m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Returning empty key.");
151 }
152 else
153 {
154 newKey = ((IAuthentication)m_userManager).GetNewKey(m_serversInfo.UserURL, userID, authKey);
155 }
156
157 XmlRpcResponse response = new XmlRpcResponse();
158 response.Value = (string) newKey;
159 return response;
160 }
161
162 public XmlRpcResponse XmlRpcVerifyKeyMethod(XmlRpcRequest request, IPEndPoint remoteClient)
163 {
164 bool success = false;
165
166 if (request.Params.Count >= 2)
167 {
168 // Verify the key of who's calling
169 UUID userID = UUID.Zero;
170 string authKey = string.Empty;
171 if (UUID.TryParse((string)request.Params[0], out userID))
172 {
173 authKey = (string)request.Params[1];
174
175 m_log.InfoFormat("[HGLOGIN] HGVerifyKey called with key {0}", authKey);
176
177 if (!(m_userManager is IAuthentication))
178 {
179 m_log.Debug("[HGLOGIN]: UserManager is not IAuthentication service. Denying.");
180 }
181 else
182 {
183 success = ((IAuthentication)m_userManager).VerifyKey(userID, authKey);
184 }
185 }
186 }
187
188 m_log.DebugFormat("[HGLOGIN]: Response to VerifyKey is {0}", success);
189 XmlRpcResponse response = new XmlRpcResponse();
190 response.Value = success;
191 return response;
192 }
193
194 public override UserProfileData GetTheUser(string firstname, string lastname)
195 {
196 UserProfileData profile = m_userManager.GetUserProfile(firstname, lastname);
197 if (profile != null)
198 {
199 return profile;
200 }
201
202 if (!m_authUsers)
203 {
204 //no current user account so make one
205 m_log.Info("[LOGIN]: No user account found so creating a new one.");
206
207 m_userManager.AddUser(firstname, lastname, "test", "", m_defaultHomeX, m_defaultHomeY);
208
209 return m_userManager.GetUserProfile(firstname, lastname);
210 }
211
212 return null;
213 }
214
215 public override bool AuthenticateUser(UserProfileData profile, string password)
216 {
217 if (!m_authUsers)
218 {
219 //for now we will accept any password in sandbox mode
220 m_log.Info("[LOGIN]: Authorising user (no actual password check)");
221
222 return true;
223 }
224 else
225 {
226 m_log.Info(
227 "[LOGIN]: Authenticating " + profile.FirstName + " " + profile.SurName);
228
229 if (!password.StartsWith("$1$"))
230 password = "$1$" + Util.Md5Hash(password);
231
232 password = password.Remove(0, 3); //remove $1$
233
234 string s = Util.Md5Hash(password + ":" + profile.PasswordSalt);
235
236 bool loginresult = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
237 || profile.PasswordHash.Equals(password, StringComparison.InvariantCulture));
238 return loginresult;
239 }
240 }
241
242 protected override RegionInfo RequestClosestRegion(string region)
243 {
244 return m_regionsConnector.RequestClosestRegion(region);
245 }
246
247 protected override RegionInfo GetRegionInfo(ulong homeRegionHandle)
248 {
249 return m_regionsConnector.RequestNeighbourInfo(homeRegionHandle);
250 }
251
252 protected override RegionInfo GetRegionInfo(UUID homeRegionId)
253 {
254 return m_regionsConnector.RequestNeighbourInfo(homeRegionId);
255 }
256
257 /// <summary>
258 /// Not really informing the region. Just filling out the response fields related to the region.
259 /// </summary>
260 /// <param name="sim"></param>
261 /// <param name="user"></param>
262 /// <param name="response"></param>
263 /// <returns>true if the region was successfully contacted, false otherwise</returns>
264 protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response, IPEndPoint remoteClient)
265 {
266 IPEndPoint endPoint = regionInfo.ExternalEndPoint;
267 response.SimAddress = endPoint.Address.ToString();
268 response.SimPort = (uint)endPoint.Port;
269 response.RegionX = regionInfo.RegionLocX;
270 response.RegionY = regionInfo.RegionLocY;
271 response.SimHttpPort = regionInfo.HttpPort;
272
273 string capsPath = CapsUtil.GetRandomCapsObjectPath();
274 string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath);
275
276 // Don't use the following! It Fails for logging into any region not on the same port as the http server!
277 // Kept here so it doesn't happen again!
278 // response.SeedCapability = regionInfo.ServerURI + capsSeedPath;
279
280 string seedcap = "http://";
281
282 if (m_serversInfo.HttpUsesSSL)
283 {
284 // For NAT
285 string host = NetworkUtil.GetHostFor(remoteClient.Address, m_serversInfo.HttpSSLCN);
286
287 seedcap = "https://" + host + ":" + m_serversInfo.httpSSLPort + capsSeedPath;
288 }
289 else
290 {
291 // For NAT
292 string host = NetworkUtil.GetHostFor(remoteClient.Address, regionInfo.ExternalHostName);
293
294 seedcap = "http://" + host + ":" + m_serversInfo.HttpListenerPort + capsSeedPath;
295 }
296
297 response.SeedCapability = seedcap;
298
299 // Notify the target of an incoming user
300 m_log.InfoFormat(
301 "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection",
302 regionInfo.RegionName, response.RegionX, response.RegionY, regionInfo.ServerURI);
303
304 // Update agent with target sim
305 user.CurrentAgent.Region = regionInfo.RegionID;
306 user.CurrentAgent.Handle = regionInfo.RegionHandle;
307
308 return true;
309 }
310
311 public override void LogOffUser(UserProfileData theUser, string message)
312 {
313 RegionInfo SimInfo;
314 try
315 {
316 SimInfo = this.m_regionsConnector.RequestNeighbourInfo(theUser.CurrentAgent.Handle);
317
318 if (SimInfo == null)
319 {
320 m_log.Error("[LOCAL LOGIN]: Region user was in isn't currently logged in");
321 return;
322 }
323 }
324 catch (Exception)
325 {
326 m_log.Error("[LOCAL LOGIN]: Unable to look up region to log user off");
327 return;
328 }
329
330 m_regionsConnector.LogOffUserFromGrid(SimInfo.RegionHandle, theUser.ID, theUser.CurrentAgent.SecureSessionID, "Logging you off");
331 }
332
333 protected override bool AllowLoginWithoutInventory()
334 {
335 return true;
336 }
337
338 }
339}
diff --git a/OpenSim/Framework/Communications/Services/LoginResponse.cs b/OpenSim/Framework/Communications/Services/LoginResponse.cs
deleted file mode 100644
index ec5f428..0000000
--- a/OpenSim/Framework/Communications/Services/LoginResponse.cs
+++ /dev/null
@@ -1,823 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nwc.XmlRpc;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36
37namespace OpenSim.Framework.Communications.Services
38{
39 /// <summary>
40 /// A temp class to handle login response.
41 /// Should make use of UserProfileManager where possible.
42 /// </summary>
43 public class LoginResponse
44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 private Hashtable loginFlagsHash;
48 private Hashtable globalTexturesHash;
49 private Hashtable loginError;
50 private Hashtable uiConfigHash;
51
52 private ArrayList loginFlags;
53 private ArrayList globalTextures;
54 private ArrayList eventCategories;
55 private ArrayList uiConfig;
56 private ArrayList classifiedCategories;
57 private ArrayList inventoryRoot;
58 private ArrayList initialOutfit;
59 private ArrayList agentInventory;
60 private ArrayList inventoryLibraryOwner;
61 private ArrayList inventoryLibRoot;
62 private ArrayList inventoryLibrary;
63 private ArrayList activeGestures;
64
65 private UserInfo userProfile;
66
67 private UUID agentID;
68 private UUID sessionID;
69 private UUID secureSessionID;
70
71 // Login Flags
72 private string dst;
73 private string stipendSinceLogin;
74 private string gendered;
75 private string everLoggedIn;
76 private string login;
77 private uint simPort;
78 private uint simHttpPort;
79 private string simAddress;
80 private string agentAccess;
81 private string agentAccessMax;
82 private Int32 circuitCode;
83 private uint regionX;
84 private uint regionY;
85
86 // Login
87 private string firstname;
88 private string lastname;
89
90 // Global Textures
91 private string sunTexture;
92 private string cloudTexture;
93 private string moonTexture;
94
95 // Error Flags
96 private string errorReason;
97 private string errorMessage;
98
99 // Response
100 private XmlRpcResponse xmlRpcResponse;
101 // private XmlRpcResponse defaultXmlRpcResponse;
102
103 private string welcomeMessage;
104 private string startLocation;
105 private string allowFirstLife;
106 private string home;
107 private string seedCapability;
108 private string lookAt;
109
110 private BuddyList m_buddyList = null;
111
112 public LoginResponse()
113 {
114 loginFlags = new ArrayList();
115 globalTextures = new ArrayList();
116 eventCategories = new ArrayList();
117 uiConfig = new ArrayList();
118 classifiedCategories = new ArrayList();
119
120 loginError = new Hashtable();
121 uiConfigHash = new Hashtable();
122
123 // defaultXmlRpcResponse = new XmlRpcResponse();
124 userProfile = new UserInfo();
125 inventoryRoot = new ArrayList();
126 initialOutfit = new ArrayList();
127 agentInventory = new ArrayList();
128 inventoryLibrary = new ArrayList();
129 inventoryLibraryOwner = new ArrayList();
130 activeGestures = new ArrayList();
131
132 xmlRpcResponse = new XmlRpcResponse();
133 // defaultXmlRpcResponse = new XmlRpcResponse();
134
135 SetDefaultValues();
136 }
137
138 private void SetDefaultValues()
139 {
140 DST = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now) ? "Y" : "N";
141 StipendSinceLogin = "N";
142 Gendered = "Y";
143 EverLoggedIn = "Y";
144 login = "false";
145 firstname = "Test";
146 lastname = "User";
147 agentAccess = "M";
148 agentAccessMax = "A";
149 startLocation = "last";
150 allowFirstLife = "Y";
151
152 SunTexture = "cce0f112-878f-4586-a2e2-a8f104bba271";
153 CloudTexture = "dc4b9f0b-d008-45c6-96a4-01dd947ac621";
154 MoonTexture = "ec4b9f0b-d008-45c6-96a4-01dd947ac621";
155
156 ErrorMessage = "You have entered an invalid name/password combination. Check Caps/lock.";
157 ErrorReason = "key";
158 welcomeMessage = "Welcome to OpenSim!";
159 seedCapability = String.Empty;
160 home = "{'region_handle':[r" + (1000*Constants.RegionSize).ToString() + ",r" + (1000*Constants.RegionSize).ToString() + "], 'position':[r" +
161 userProfile.homepos.X.ToString() + ",r" + userProfile.homepos.Y.ToString() + ",r" +
162 userProfile.homepos.Z.ToString() + "], 'look_at':[r" + userProfile.homelookat.X.ToString() + ",r" +
163 userProfile.homelookat.Y.ToString() + ",r" + userProfile.homelookat.Z.ToString() + "]}";
164 lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]";
165 RegionX = (uint) 255232;
166 RegionY = (uint) 254976;
167
168 // Classifieds;
169 AddClassifiedCategory((Int32) 1, "Shopping");
170 AddClassifiedCategory((Int32) 2, "Land Rental");
171 AddClassifiedCategory((Int32) 3, "Property Rental");
172 AddClassifiedCategory((Int32) 4, "Special Attraction");
173 AddClassifiedCategory((Int32) 5, "New Products");
174 AddClassifiedCategory((Int32) 6, "Employment");
175 AddClassifiedCategory((Int32) 7, "Wanted");
176 AddClassifiedCategory((Int32) 8, "Service");
177 AddClassifiedCategory((Int32) 9, "Personal");
178
179 SessionID = UUID.Random();
180 SecureSessionID = UUID.Random();
181 AgentID = UUID.Random();
182
183 Hashtable InitialOutfitHash = new Hashtable();
184 InitialOutfitHash["folder_name"] = "Nightclub Female";
185 InitialOutfitHash["gender"] = "female";
186 initialOutfit.Add(InitialOutfitHash);
187 }
188
189 #region Login Failure Methods
190
191 public XmlRpcResponse GenerateFailureResponse(string reason, string message, string login)
192 {
193 // Overwrite any default values;
194 xmlRpcResponse = new XmlRpcResponse();
195
196 // Ensure Login Failed message/reason;
197 ErrorMessage = message;
198 ErrorReason = reason;
199
200 loginError["reason"] = ErrorReason;
201 loginError["message"] = ErrorMessage;
202 loginError["login"] = login;
203 xmlRpcResponse.Value = loginError;
204 return (xmlRpcResponse);
205 }
206
207 public OSD GenerateFailureResponseLLSD(string reason, string message, string login)
208 {
209 OSDMap map = new OSDMap();
210
211 // Ensure Login Failed message/reason;
212 ErrorMessage = message;
213 ErrorReason = reason;
214
215 map["reason"] = OSD.FromString(ErrorReason);
216 map["message"] = OSD.FromString(ErrorMessage);
217 map["login"] = OSD.FromString(login);
218
219 return map;
220 }
221
222 public XmlRpcResponse CreateFailedResponse()
223 {
224 return (CreateLoginFailedResponse());
225 }
226
227 public OSD CreateFailedResponseLLSD()
228 {
229 return CreateLoginFailedResponseLLSD();
230 }
231
232 public XmlRpcResponse CreateLoginFailedResponse()
233 {
234 return
235 (GenerateFailureResponse("key",
236 "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist.",
237 "false"));
238 }
239
240 public OSD CreateLoginFailedResponseLLSD()
241 {
242 return GenerateFailureResponseLLSD(
243 "key",
244 "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist.",
245 "false");
246 }
247
248 /// <summary>
249 /// Response to indicate that login failed because the agent's inventory was not available.
250 /// </summary>
251 /// <returns></returns>
252 public XmlRpcResponse CreateLoginInventoryFailedResponse()
253 {
254 return GenerateFailureResponse(
255 "key",
256 "The avatar inventory service is not responding. Please notify your login region operator.",
257 "false");
258 }
259
260 public XmlRpcResponse CreateAlreadyLoggedInResponse()
261 {
262 return
263 (GenerateFailureResponse("presence",
264 "You appear to be already logged in. " +
265 "If this is not the case please wait for your session to timeout. " +
266 "If this takes longer than a few minutes please contact the grid owner. " +
267 "Please wait 5 minutes if you are going to connect to a region nearby to the region you were at previously.",
268 "false"));
269 }
270
271 public OSD CreateAlreadyLoggedInResponseLLSD()
272 {
273 return GenerateFailureResponseLLSD(
274 "presence",
275 "You appear to be already logged in. " +
276 "If this is not the case please wait for your session to timeout. " +
277 "If this takes longer than a few minutes please contact the grid owner",
278 "false");
279 }
280
281 public XmlRpcResponse CreateLoginBlockedResponse()
282 {
283 return
284 (GenerateFailureResponse("presence",
285 "Logins are currently restricted. Please try again later",
286 "false"));
287 }
288
289 public OSD CreateLoginBlockedResponseLLSD()
290 {
291 return GenerateFailureResponseLLSD(
292 "presence",
293 "Logins are currently restricted. Please try again later",
294 "false");
295 }
296
297 public XmlRpcResponse CreateDeadRegionResponse()
298 {
299 return
300 (GenerateFailureResponse("key",
301 "The region you are attempting to log into is not responding. Please select another region and try again.",
302 "false"));
303 }
304
305 public OSD CreateDeadRegionResponseLLSD()
306 {
307 return GenerateFailureResponseLLSD(
308 "key",
309 "The region you are attempting to log into is not responding. Please select another region and try again.",
310 "false");
311 }
312
313 public XmlRpcResponse CreateGridErrorResponse()
314 {
315 return
316 (GenerateFailureResponse("key",
317 "Error connecting to grid. Could not percieve credentials from login XML.",
318 "false"));
319 }
320
321 public OSD CreateGridErrorResponseLLSD()
322 {
323 return GenerateFailureResponseLLSD(
324 "key",
325 "Error connecting to grid. Could not perceive credentials from login XML.",
326 "false");
327 }
328
329 #endregion
330
331 public virtual XmlRpcResponse ToXmlRpcResponse()
332 {
333 try
334 {
335 Hashtable responseData = new Hashtable();
336
337 loginFlagsHash = new Hashtable();
338 loginFlagsHash["daylight_savings"] = DST;
339 loginFlagsHash["stipend_since_login"] = StipendSinceLogin;
340 loginFlagsHash["gendered"] = Gendered;
341 loginFlagsHash["ever_logged_in"] = EverLoggedIn;
342 loginFlags.Add(loginFlagsHash);
343
344 responseData["first_name"] = Firstname;
345 responseData["last_name"] = Lastname;
346 responseData["agent_access"] = agentAccess;
347 responseData["agent_access_max"] = agentAccessMax;
348
349 globalTexturesHash = new Hashtable();
350 globalTexturesHash["sun_texture_id"] = SunTexture;
351 globalTexturesHash["cloud_texture_id"] = CloudTexture;
352 globalTexturesHash["moon_texture_id"] = MoonTexture;
353 globalTextures.Add(globalTexturesHash);
354 // this.eventCategories.Add(this.eventCategoriesHash);
355
356 AddToUIConfig("allow_first_life", allowFirstLife);
357 uiConfig.Add(uiConfigHash);
358
359 responseData["sim_port"] = (Int32) SimPort;
360 responseData["sim_ip"] = SimAddress;
361 responseData["http_port"] = (Int32)SimHttpPort;
362
363 responseData["agent_id"] = AgentID.ToString();
364 responseData["session_id"] = SessionID.ToString();
365 responseData["secure_session_id"] = SecureSessionID.ToString();
366 responseData["circuit_code"] = CircuitCode;
367 responseData["seconds_since_epoch"] = (Int32) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
368 responseData["login-flags"] = loginFlags;
369 responseData["global-textures"] = globalTextures;
370 responseData["seed_capability"] = seedCapability;
371
372 responseData["event_categories"] = eventCategories;
373 responseData["event_notifications"] = new ArrayList(); // todo
374 responseData["classified_categories"] = classifiedCategories;
375 responseData["ui-config"] = uiConfig;
376
377 if (agentInventory != null)
378 {
379 responseData["inventory-skeleton"] = agentInventory;
380 responseData["inventory-root"] = inventoryRoot;
381 }
382 responseData["inventory-skel-lib"] = inventoryLibrary;
383 responseData["inventory-lib-root"] = inventoryLibRoot;
384 responseData["gestures"] = activeGestures;
385 responseData["inventory-lib-owner"] = inventoryLibraryOwner;
386 responseData["initial-outfit"] = initialOutfit;
387 responseData["start_location"] = startLocation;
388 responseData["seed_capability"] = seedCapability;
389 responseData["home"] = home;
390 responseData["look_at"] = lookAt;
391 responseData["message"] = welcomeMessage;
392 responseData["region_x"] = (Int32)(RegionX * Constants.RegionSize);
393 responseData["region_y"] = (Int32)(RegionY * Constants.RegionSize);
394
395 if (m_buddyList != null)
396 {
397 responseData["buddy-list"] = m_buddyList.ToArray();
398 }
399
400 responseData["login"] = "true";
401 xmlRpcResponse.Value = responseData;
402
403 return (xmlRpcResponse);
404 }
405 catch (Exception e)
406 {
407 m_log.Warn("[CLIENT]: LoginResponse: Error creating XML-RPC Response: " + e.Message);
408
409 return (GenerateFailureResponse("Internal Error", "Error generating Login Response", "false"));
410 }
411 }
412
413 public OSD ToLLSDResponse()
414 {
415 try
416 {
417 OSDMap map = new OSDMap();
418
419 map["first_name"] = OSD.FromString(Firstname);
420 map["last_name"] = OSD.FromString(Lastname);
421 map["agent_access"] = OSD.FromString(agentAccess);
422 map["agent_access_max"] = OSD.FromString(agentAccessMax);
423
424 map["sim_port"] = OSD.FromInteger(SimPort);
425 map["sim_ip"] = OSD.FromString(SimAddress);
426
427 map["agent_id"] = OSD.FromUUID(AgentID);
428 map["session_id"] = OSD.FromUUID(SessionID);
429 map["secure_session_id"] = OSD.FromUUID(SecureSessionID);
430 map["circuit_code"] = OSD.FromInteger(CircuitCode);
431 map["seconds_since_epoch"] = OSD.FromInteger((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds);
432
433 #region Login Flags
434
435 OSDMap loginFlagsLLSD = new OSDMap();
436 loginFlagsLLSD["daylight_savings"] = OSD.FromString(DST);
437 loginFlagsLLSD["stipend_since_login"] = OSD.FromString(StipendSinceLogin);
438 loginFlagsLLSD["gendered"] = OSD.FromString(Gendered);
439 loginFlagsLLSD["ever_logged_in"] = OSD.FromString(EverLoggedIn);
440 map["login-flags"] = WrapOSDMap(loginFlagsLLSD);
441
442 #endregion Login Flags
443
444 #region Global Textures
445
446 OSDMap globalTexturesLLSD = new OSDMap();
447 globalTexturesLLSD["sun_texture_id"] = OSD.FromString(SunTexture);
448 globalTexturesLLSD["cloud_texture_id"] = OSD.FromString(CloudTexture);
449 globalTexturesLLSD["moon_texture_id"] = OSD.FromString(MoonTexture);
450
451 map["global-textures"] = WrapOSDMap(globalTexturesLLSD);
452
453 #endregion Global Textures
454
455 map["seed_capability"] = OSD.FromString(seedCapability);
456
457 map["event_categories"] = ArrayListToOSDArray(eventCategories);
458 //map["event_notifications"] = new OSDArray(); // todo
459 map["classified_categories"] = ArrayListToOSDArray(classifiedCategories);
460
461 #region UI Config
462
463 OSDMap uiConfigLLSD = new OSDMap();
464 uiConfigLLSD["allow_first_life"] = OSD.FromString(allowFirstLife);
465 map["ui-config"] = WrapOSDMap(uiConfigLLSD);
466
467 #endregion UI Config
468
469 #region Inventory
470
471 map["inventory-skeleton"] = ArrayListToOSDArray(agentInventory);
472
473 map["inventory-skel-lib"] = ArrayListToOSDArray(inventoryLibrary);
474 map["inventory-root"] = ArrayListToOSDArray(inventoryRoot); ;
475 map["inventory-lib-root"] = ArrayListToOSDArray(inventoryLibRoot);
476 map["inventory-lib-owner"] = ArrayListToOSDArray(inventoryLibraryOwner);
477
478 #endregion Inventory
479
480 map["gestures"] = ArrayListToOSDArray(activeGestures);
481
482 map["initial-outfit"] = ArrayListToOSDArray(initialOutfit);
483 map["start_location"] = OSD.FromString(startLocation);
484
485 map["seed_capability"] = OSD.FromString(seedCapability);
486 map["home"] = OSD.FromString(home);
487 map["look_at"] = OSD.FromString(lookAt);
488 map["message"] = OSD.FromString(welcomeMessage);
489 map["region_x"] = OSD.FromInteger(RegionX * Constants.RegionSize);
490 map["region_y"] = OSD.FromInteger(RegionY * Constants.RegionSize);
491
492 if (m_buddyList != null)
493 {
494 map["buddy-list"] = ArrayListToOSDArray(m_buddyList.ToArray());
495 }
496
497 map["login"] = OSD.FromString("true");
498
499 return map;
500 }
501 catch (Exception e)
502 {
503 m_log.Warn("[CLIENT]: LoginResponse: Error creating LLSD Response: " + e.Message);
504
505 return GenerateFailureResponseLLSD("Internal Error", "Error generating Login Response", "false");
506 }
507 }
508
509 public OSDArray ArrayListToOSDArray(ArrayList arrlst)
510 {
511 OSDArray llsdBack = new OSDArray();
512 foreach (Hashtable ht in arrlst)
513 {
514 OSDMap mp = new OSDMap();
515 foreach (DictionaryEntry deHt in ht)
516 {
517 mp.Add((string)deHt.Key, OSDString.FromObject(deHt.Value));
518 }
519 llsdBack.Add(mp);
520 }
521 return llsdBack;
522 }
523
524 private static OSDArray WrapOSDMap(OSDMap wrapMe)
525 {
526 OSDArray array = new OSDArray();
527 array.Add(wrapMe);
528 return array;
529 }
530
531 public void SetEventCategories(string category, string value)
532 {
533 // this.eventCategoriesHash[category] = value;
534 //TODO
535 }
536
537 public void AddToUIConfig(string itemName, string item)
538 {
539 uiConfigHash[itemName] = item;
540 }
541
542 public void AddClassifiedCategory(Int32 ID, string categoryName)
543 {
544 Hashtable hash = new Hashtable();
545 hash["category_name"] = categoryName;
546 hash["category_id"] = ID;
547 classifiedCategories.Add(hash);
548 // this.classifiedCategoriesHash.Clear();
549 }
550
551 #region Properties
552
553 public string Login
554 {
555 get { return login; }
556 set { login = value; }
557 }
558
559 public string DST
560 {
561 get { return dst; }
562 set { dst = value; }
563 }
564
565 public string StipendSinceLogin
566 {
567 get { return stipendSinceLogin; }
568 set { stipendSinceLogin = value; }
569 }
570
571 public string Gendered
572 {
573 get { return gendered; }
574 set { gendered = value; }
575 }
576
577 public string EverLoggedIn
578 {
579 get { return everLoggedIn; }
580 set { everLoggedIn = value; }
581 }
582
583 public uint SimPort
584 {
585 get { return simPort; }
586 set { simPort = value; }
587 }
588
589 public uint SimHttpPort
590 {
591 get { return simHttpPort; }
592 set { simHttpPort = value; }
593 }
594
595 public string SimAddress
596 {
597 get { return simAddress; }
598 set { simAddress = value; }
599 }
600
601 public UUID AgentID
602 {
603 get { return agentID; }
604 set { agentID = value; }
605 }
606
607 public UUID SessionID
608 {
609 get { return sessionID; }
610 set { sessionID = value; }
611 }
612
613 public UUID SecureSessionID
614 {
615 get { return secureSessionID; }
616 set { secureSessionID = value; }
617 }
618
619 public Int32 CircuitCode
620 {
621 get { return circuitCode; }
622 set { circuitCode = value; }
623 }
624
625 public uint RegionX
626 {
627 get { return regionX; }
628 set { regionX = value; }
629 }
630
631 public uint RegionY
632 {
633 get { return regionY; }
634 set { regionY = value; }
635 }
636
637 public string SunTexture
638 {
639 get { return sunTexture; }
640 set { sunTexture = value; }
641 }
642
643 public string CloudTexture
644 {
645 get { return cloudTexture; }
646 set { cloudTexture = value; }
647 }
648
649 public string MoonTexture
650 {
651 get { return moonTexture; }
652 set { moonTexture = value; }
653 }
654
655 public string Firstname
656 {
657 get { return firstname; }
658 set { firstname = value; }
659 }
660
661 public string Lastname
662 {
663 get { return lastname; }
664 set { lastname = value; }
665 }
666
667 public string AgentAccess
668 {
669 get { return agentAccess; }
670 set { agentAccess = value; }
671 }
672
673 public string AgentAccessMax
674 {
675 get { return agentAccessMax; }
676 set { agentAccessMax = value; }
677 }
678
679 public string StartLocation
680 {
681 get { return startLocation; }
682 set { startLocation = value; }
683 }
684
685 public string LookAt
686 {
687 get { return lookAt; }
688 set { lookAt = value; }
689 }
690
691 public string SeedCapability
692 {
693 get { return seedCapability; }
694 set { seedCapability = value; }
695 }
696
697 public string ErrorReason
698 {
699 get { return errorReason; }
700 set { errorReason = value; }
701 }
702
703 public string ErrorMessage
704 {
705 get { return errorMessage; }
706 set { errorMessage = value; }
707 }
708
709 public ArrayList InventoryRoot
710 {
711 get { return inventoryRoot; }
712 set { inventoryRoot = value; }
713 }
714
715 public ArrayList InventorySkeleton
716 {
717 get { return agentInventory; }
718 set { agentInventory = value; }
719 }
720
721 public ArrayList InventoryLibrary
722 {
723 get { return inventoryLibrary; }
724 set { inventoryLibrary = value; }
725 }
726
727 public ArrayList InventoryLibraryOwner
728 {
729 get { return inventoryLibraryOwner; }
730 set { inventoryLibraryOwner = value; }
731 }
732
733 public ArrayList InventoryLibRoot
734 {
735 get { return inventoryLibRoot; }
736 set { inventoryLibRoot = value; }
737 }
738
739 public ArrayList ActiveGestures
740 {
741 get { return activeGestures; }
742 set { activeGestures = value; }
743 }
744
745 public string Home
746 {
747 get { return home; }
748 set { home = value; }
749 }
750
751 public string Message
752 {
753 get { return welcomeMessage; }
754 set { welcomeMessage = value; }
755 }
756
757 public BuddyList BuddList
758 {
759 get { return m_buddyList; }
760 set { m_buddyList = value; }
761 }
762
763 #endregion
764
765 public class UserInfo
766 {
767 public string firstname;
768 public string lastname;
769 public ulong homeregionhandle;
770 public Vector3 homepos;
771 public Vector3 homelookat;
772 }
773
774 public class BuddyList
775 {
776 public List<BuddyInfo> Buddies = new List<BuddyInfo>();
777
778 public void AddNewBuddy(BuddyInfo buddy)
779 {
780 if (!Buddies.Contains(buddy))
781 {
782 Buddies.Add(buddy);
783 }
784 }
785
786 public ArrayList ToArray()
787 {
788 ArrayList buddyArray = new ArrayList();
789 foreach (BuddyInfo buddy in Buddies)
790 {
791 buddyArray.Add(buddy.ToHashTable());
792 }
793 return buddyArray;
794 }
795
796 public class BuddyInfo
797 {
798 public int BuddyRightsHave = 1;
799 public int BuddyRightsGiven = 1;
800 public UUID BuddyID;
801
802 public BuddyInfo(string buddyID)
803 {
804 BuddyID = new UUID(buddyID);
805 }
806
807 public BuddyInfo(UUID buddyID)
808 {
809 BuddyID = buddyID;
810 }
811
812 public Hashtable ToHashTable()
813 {
814 Hashtable hTable = new Hashtable();
815 hTable["buddy_rights_has"] = BuddyRightsHave;
816 hTable["buddy_rights_given"] = BuddyRightsGiven;
817 hTable["buddy_id"] = BuddyID.ToString();
818 return hTable;
819 }
820 }
821 }
822 }
823}
diff --git a/OpenSim/Framework/Communications/Services/LoginService.cs b/OpenSim/Framework/Communications/Services/LoginService.cs
deleted file mode 100644
index 824cc57..0000000
--- a/OpenSim/Framework/Communications/Services/LoginService.cs
+++ /dev/null
@@ -1,1241 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net;
33using System.Reflection;
34using System.Text.RegularExpressions;
35using System.Threading;
36using System.Web;
37using log4net;
38using Nwc.XmlRpc;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenSim.Framework;
42using OpenSim.Framework.Communications.Cache;
43using OpenSim.Framework.Statistics;
44using OpenSim.Services.Interfaces;
45
46namespace OpenSim.Framework.Communications.Services
47{
48 public abstract class LoginService
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 protected string m_welcomeMessage = "Welcome to OpenSim";
53 protected int m_minLoginLevel = 0;
54 protected UserManagerBase m_userManager = null;
55 protected Mutex m_loginMutex = new Mutex(false);
56
57 /// <summary>
58 /// Used during login to send the skeleton of the OpenSim Library to the client.
59 /// </summary>
60 protected LibraryRootFolder m_libraryRootFolder;
61
62 protected uint m_defaultHomeX;
63 protected uint m_defaultHomeY;
64
65 protected bool m_warn_already_logged = true;
66
67 /// <summary>
68 /// Used by the login service to make requests to the inventory service.
69 /// </summary>
70 protected IInterServiceInventoryServices m_interInventoryService;
71 // Hack
72 protected IInventoryService m_InventoryService;
73
74 /// <summary>
75 /// Constructor
76 /// </summary>
77 /// <param name="userManager"></param>
78 /// <param name="libraryRootFolder"></param>
79 /// <param name="welcomeMess"></param>
80 public LoginService(UserManagerBase userManager, LibraryRootFolder libraryRootFolder,
81 string welcomeMess)
82 {
83 m_userManager = userManager;
84 m_libraryRootFolder = libraryRootFolder;
85
86 if (welcomeMess != String.Empty)
87 {
88 m_welcomeMessage = welcomeMess;
89 }
90 }
91
92 /// <summary>
93 /// Called when we receive the client's initial XMLRPC login_to_simulator request message
94 /// </summary>
95 /// <param name="request">The XMLRPC request</param>
96 /// <returns>The response to send</returns>
97 public virtual XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request, IPEndPoint remoteClient)
98 {
99 // Temporary fix
100 m_loginMutex.WaitOne();
101
102 try
103 {
104 //CFK: CustomizeResponse contains sufficient strings to alleviate the need for this.
105 //CKF: m_log.Info("[LOGIN]: Attempting login now...");
106 XmlRpcResponse response = new XmlRpcResponse();
107 Hashtable requestData = (Hashtable)request.Params[0];
108
109 SniffLoginKey((Uri)request.Params[2], requestData);
110
111 bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") &&
112 (requestData.Contains("passwd") || requestData.Contains("web_login_key")));
113
114 string startLocationRequest = "last";
115
116 UserProfileData userProfile;
117 LoginResponse logResponse = new LoginResponse();
118
119 string firstname;
120 string lastname;
121
122 if (GoodXML)
123 {
124 if (requestData.Contains("start"))
125 {
126 startLocationRequest = (string)requestData["start"];
127 }
128
129 firstname = (string)requestData["first"];
130 lastname = (string)requestData["last"];
131
132 m_log.InfoFormat(
133 "[LOGIN BEGIN]: XMLRPC Received login request message from user '{0}' '{1}'",
134 firstname, lastname);
135
136 string clientVersion = "Unknown";
137
138 if (requestData.Contains("version"))
139 {
140 clientVersion = (string)requestData["version"];
141 }
142
143 m_log.DebugFormat(
144 "[LOGIN]: XMLRPC Client is {0}, start location is {1}", clientVersion, startLocationRequest);
145
146 if (!TryAuthenticateXmlRpcLogin(request, firstname, lastname, out userProfile))
147 {
148 return logResponse.CreateLoginFailedResponse();
149 }
150 }
151 else
152 {
153 m_log.Info(
154 "[LOGIN END]: XMLRPC login_to_simulator login message did not contain all the required data");
155
156 return logResponse.CreateGridErrorResponse();
157 }
158
159 if (userProfile.GodLevel < m_minLoginLevel)
160 {
161 return logResponse.CreateLoginBlockedResponse();
162 }
163 else
164 {
165 // If we already have a session...
166 if (userProfile.CurrentAgent != null && userProfile.CurrentAgent.AgentOnline)
167 {
168 //TODO: The following statements can cause trouble:
169 // If agentOnline could not turn from true back to false normally
170 // because of some problem, for instance, the crashment of server or client,
171 // the user cannot log in any longer.
172 userProfile.CurrentAgent.AgentOnline = false;
173
174 m_userManager.CommitAgent(ref userProfile);
175
176 // try to tell the region that their user is dead.
177 LogOffUser(userProfile, " XMLRPC You were logged off because you logged in from another location");
178
179 if (m_warn_already_logged)
180 {
181 // This is behavior for for grid, reject login
182 m_log.InfoFormat(
183 "[LOGIN END]: XMLRPC Notifying user {0} {1} that they are already logged in",
184 firstname, lastname);
185
186 return logResponse.CreateAlreadyLoggedInResponse();
187 }
188 else
189 {
190 // This is behavior for standalone (silent logout of last hung session)
191 m_log.InfoFormat(
192 "[LOGIN]: XMLRPC User {0} {1} is already logged in, not notifying user, kicking old presence and starting new login.",
193 firstname, lastname);
194 }
195 }
196
197 // Otherwise...
198 // Create a new agent session
199
200 // XXYY we don't need this
201 //m_userManager.ResetAttachments(userProfile.ID);
202
203 CreateAgent(userProfile, request);
204
205 // We need to commit the agent right here, even though the userProfile info is not complete
206 // at this point. There is another commit further down.
207 // This is for the new sessionID to be stored so that the region can check it for session authentication.
208 // CustomiseResponse->PrepareLoginToRegion
209 CommitAgent(ref userProfile);
210
211 try
212 {
213 UUID agentID = userProfile.ID;
214 InventoryData inventData = null;
215
216 try
217 {
218 inventData = GetInventorySkeleton(agentID);
219 }
220 catch (Exception e)
221 {
222 m_log.ErrorFormat(
223 "[LOGIN END]: Error retrieving inventory skeleton of agent {0} - {1}",
224 agentID, e);
225
226 // Let's not panic
227 if (!AllowLoginWithoutInventory())
228 return logResponse.CreateLoginInventoryFailedResponse();
229 }
230
231 if (inventData != null)
232 {
233 ArrayList AgentInventoryArray = inventData.InventoryArray;
234
235 Hashtable InventoryRootHash = new Hashtable();
236 InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString();
237 ArrayList InventoryRoot = new ArrayList();
238 InventoryRoot.Add(InventoryRootHash);
239
240 logResponse.InventoryRoot = InventoryRoot;
241 logResponse.InventorySkeleton = AgentInventoryArray;
242 }
243
244 // Inventory Library Section
245 Hashtable InventoryLibRootHash = new Hashtable();
246 InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000";
247 ArrayList InventoryLibRoot = new ArrayList();
248 InventoryLibRoot.Add(InventoryLibRootHash);
249
250 logResponse.InventoryLibRoot = InventoryLibRoot;
251 logResponse.InventoryLibraryOwner = GetLibraryOwner();
252 logResponse.InventoryLibrary = GetInventoryLibrary();
253
254 logResponse.CircuitCode = Util.RandomClass.Next();
255 logResponse.Lastname = userProfile.SurName;
256 logResponse.Firstname = userProfile.FirstName;
257 logResponse.AgentID = agentID;
258 logResponse.SessionID = userProfile.CurrentAgent.SessionID;
259 logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID;
260 logResponse.Message = GetMessage();
261 logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID));
262 logResponse.StartLocation = startLocationRequest;
263
264 if (CustomiseResponse(logResponse, userProfile, startLocationRequest, remoteClient))
265 {
266 userProfile.LastLogin = userProfile.CurrentAgent.LoginTime;
267 CommitAgent(ref userProfile);
268
269 // If we reach this point, then the login has successfully logged onto the grid
270 if (StatsManager.UserStats != null)
271 StatsManager.UserStats.AddSuccessfulLogin();
272
273 m_log.DebugFormat(
274 "[LOGIN END]: XMLRPC Authentication of user {0} {1} successful. Sending response to client.",
275 firstname, lastname);
276
277 return logResponse.ToXmlRpcResponse();
278 }
279 else
280 {
281 m_log.ErrorFormat("[LOGIN END]: XMLRPC informing user {0} {1} that login failed due to an unavailable region", firstname, lastname);
282 return logResponse.CreateDeadRegionResponse();
283 }
284 }
285 catch (Exception e)
286 {
287 m_log.Error("[LOGIN END]: XMLRPC Login failed, " + e);
288 m_log.Error(e.StackTrace);
289 }
290 }
291
292 m_log.Info("[LOGIN END]: XMLRPC Login failed. Sending back blank XMLRPC response");
293 return response;
294 }
295 finally
296 {
297 m_loginMutex.ReleaseMutex();
298 }
299 }
300
301 protected virtual bool TryAuthenticateXmlRpcLogin(
302 XmlRpcRequest request, string firstname, string lastname, out UserProfileData userProfile)
303 {
304 Hashtable requestData = (Hashtable)request.Params[0];
305
306 userProfile = GetTheUser(firstname, lastname);
307 if (userProfile == null)
308 {
309 m_log.Debug("[LOGIN END]: XMLRPC Could not find a profile for " + firstname + " " + lastname);
310 return false;
311 }
312 else
313 {
314 if (requestData.Contains("passwd"))
315 {
316 string passwd = (string)requestData["passwd"];
317 bool authenticated = AuthenticateUser(userProfile, passwd);
318
319 if (!authenticated)
320 m_log.DebugFormat("[LOGIN END]: XMLRPC User {0} {1} failed password authentication",
321 firstname, lastname);
322
323 return authenticated;
324 }
325
326 if (requestData.Contains("web_login_key"))
327 {
328 try
329 {
330 UUID webloginkey = new UUID((string)requestData["web_login_key"]);
331 bool authenticated = AuthenticateUser(userProfile, webloginkey);
332
333 if (!authenticated)
334 m_log.DebugFormat("[LOGIN END]: XMLRPC User {0} {1} failed web login key authentication",
335 firstname, lastname);
336
337 return authenticated;
338 }
339 catch (Exception e)
340 {
341 m_log.DebugFormat(
342 "[LOGIN END]: XMLRPC Bad web_login_key: {0} for user {1} {2}, exception {3}",
343 requestData["web_login_key"], firstname, lastname, e);
344
345 return false;
346 }
347 }
348
349 m_log.DebugFormat(
350 "[LOGIN END]: XMLRPC login request for {0} {1} contained neither a password nor a web login key",
351 firstname, lastname);
352 }
353
354 return false;
355 }
356
357 protected virtual bool TryAuthenticateLLSDLogin(string firstname, string lastname, string passwd, out UserProfileData userProfile)
358 {
359 bool GoodLogin = false;
360 userProfile = GetTheUser(firstname, lastname);
361 if (userProfile == null)
362 {
363 m_log.Info("[LOGIN]: LLSD Could not find a profile for " + firstname + " " + lastname);
364
365 return false;
366 }
367
368 GoodLogin = AuthenticateUser(userProfile, passwd);
369 return GoodLogin;
370 }
371
372 /// <summary>
373 /// Called when we receive the client's initial LLSD login_to_simulator request message
374 /// </summary>
375 /// <param name="request">The LLSD request</param>
376 /// <returns>The response to send</returns>
377 public OSD LLSDLoginMethod(OSD request, IPEndPoint remoteClient)
378 {
379 // Temporary fix
380 m_loginMutex.WaitOne();
381
382 try
383 {
384 // bool GoodLogin = false;
385
386 string startLocationRequest = "last";
387
388 UserProfileData userProfile = null;
389 LoginResponse logResponse = new LoginResponse();
390
391 if (request.Type == OSDType.Map)
392 {
393 OSDMap map = (OSDMap)request;
394
395 if (map.ContainsKey("first") && map.ContainsKey("last") && map.ContainsKey("passwd"))
396 {
397 string firstname = map["first"].AsString();
398 string lastname = map["last"].AsString();
399 string passwd = map["passwd"].AsString();
400
401 if (map.ContainsKey("start"))
402 {
403 m_log.Info("[LOGIN]: LLSD StartLocation Requested: " + map["start"].AsString());
404 startLocationRequest = map["start"].AsString();
405 }
406 m_log.Info("[LOGIN]: LLSD Login Requested for: '" + firstname + "' '" + lastname + "' / " + passwd);
407
408 if (!TryAuthenticateLLSDLogin(firstname, lastname, passwd, out userProfile))
409 {
410 return logResponse.CreateLoginFailedResponseLLSD();
411 }
412 }
413 else
414 return logResponse.CreateLoginFailedResponseLLSD();
415 }
416 else
417 return logResponse.CreateLoginFailedResponseLLSD();
418
419
420 if (userProfile.GodLevel < m_minLoginLevel)
421 {
422 return logResponse.CreateLoginBlockedResponseLLSD();
423 }
424 else
425 {
426 // If we already have a session...
427 if (userProfile.CurrentAgent != null && userProfile.CurrentAgent.AgentOnline)
428 {
429 userProfile.CurrentAgent.AgentOnline = false;
430
431 m_userManager.CommitAgent(ref userProfile);
432 // try to tell the region that their user is dead.
433 LogOffUser(userProfile, " LLSD You were logged off because you logged in from another location");
434
435 if (m_warn_already_logged)
436 {
437 // This is behavior for for grid, reject login
438 m_log.InfoFormat(
439 "[LOGIN END]: LLSD Notifying user {0} {1} that they are already logged in",
440 userProfile.FirstName, userProfile.SurName);
441
442 userProfile.CurrentAgent = null;
443 return logResponse.CreateAlreadyLoggedInResponseLLSD();
444 }
445 else
446 {
447 // This is behavior for standalone (silent logout of last hung session)
448 m_log.InfoFormat(
449 "[LOGIN]: LLSD User {0} {1} is already logged in, not notifying user, kicking old presence and starting new login.",
450 userProfile.FirstName, userProfile.SurName);
451 }
452 }
453
454 // Otherwise...
455 // Create a new agent session
456
457 // XXYY We don't need this
458 //m_userManager.ResetAttachments(userProfile.ID);
459
460 CreateAgent(userProfile, request);
461
462 // We need to commit the agent right here, even though the userProfile info is not complete
463 // at this point. There is another commit further down.
464 // This is for the new sessionID to be stored so that the region can check it for session authentication.
465 // CustomiseResponse->PrepareLoginToRegion
466 CommitAgent(ref userProfile);
467
468 try
469 {
470 UUID agentID = userProfile.ID;
471
472 //InventoryData inventData = GetInventorySkeleton(agentID);
473 InventoryData inventData = null;
474
475 try
476 {
477 inventData = GetInventorySkeleton(agentID);
478 }
479 catch (Exception e)
480 {
481 m_log.ErrorFormat(
482 "[LOGIN END]: LLSD Error retrieving inventory skeleton of agent {0}, {1} - {2}",
483 agentID, e.GetType(), e.Message);
484
485 return logResponse.CreateLoginFailedResponseLLSD();// .CreateLoginInventoryFailedResponseLLSD ();
486 }
487
488
489 ArrayList AgentInventoryArray = inventData.InventoryArray;
490
491 Hashtable InventoryRootHash = new Hashtable();
492 InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString();
493 ArrayList InventoryRoot = new ArrayList();
494 InventoryRoot.Add(InventoryRootHash);
495
496
497 // Inventory Library Section
498 Hashtable InventoryLibRootHash = new Hashtable();
499 InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000";
500 ArrayList InventoryLibRoot = new ArrayList();
501 InventoryLibRoot.Add(InventoryLibRootHash);
502
503 logResponse.InventoryLibRoot = InventoryLibRoot;
504 logResponse.InventoryLibraryOwner = GetLibraryOwner();
505 logResponse.InventoryRoot = InventoryRoot;
506 logResponse.InventorySkeleton = AgentInventoryArray;
507 logResponse.InventoryLibrary = GetInventoryLibrary();
508
509 logResponse.CircuitCode = (Int32)Util.RandomClass.Next();
510 logResponse.Lastname = userProfile.SurName;
511 logResponse.Firstname = userProfile.FirstName;
512 logResponse.AgentID = agentID;
513 logResponse.SessionID = userProfile.CurrentAgent.SessionID;
514 logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID;
515 logResponse.Message = GetMessage();
516 logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID));
517 logResponse.StartLocation = startLocationRequest;
518
519 try
520 {
521 CustomiseResponse(logResponse, userProfile, startLocationRequest, remoteClient);
522 }
523 catch (Exception ex)
524 {
525 m_log.Info("[LOGIN]: LLSD " + ex.ToString());
526 return logResponse.CreateDeadRegionResponseLLSD();
527 }
528
529 userProfile.LastLogin = userProfile.CurrentAgent.LoginTime;
530 CommitAgent(ref userProfile);
531
532 // If we reach this point, then the login has successfully logged onto the grid
533 if (StatsManager.UserStats != null)
534 StatsManager.UserStats.AddSuccessfulLogin();
535
536 m_log.DebugFormat(
537 "[LOGIN END]: LLSD Authentication of user {0} {1} successful. Sending response to client.",
538 userProfile.FirstName, userProfile.SurName);
539
540 return logResponse.ToLLSDResponse();
541 }
542 catch (Exception ex)
543 {
544 m_log.Info("[LOGIN]: LLSD " + ex.ToString());
545 return logResponse.CreateFailedResponseLLSD();
546 }
547 }
548 }
549 finally
550 {
551 m_loginMutex.ReleaseMutex();
552 }
553 }
554
555 public Hashtable ProcessHTMLLogin(Hashtable keysvals)
556 {
557 // Matches all unspecified characters
558 // Currently specified,; lowercase letters, upper case letters, numbers, underline
559 // period, space, parens, and dash.
560
561 Regex wfcut = new Regex("[^a-zA-Z0-9_\\.\\$ \\(\\)\\-]");
562
563 Hashtable returnactions = new Hashtable();
564 int statuscode = 200;
565
566 string firstname = String.Empty;
567 string lastname = String.Empty;
568 string location = String.Empty;
569 string region = String.Empty;
570 string grid = String.Empty;
571 string channel = String.Empty;
572 string version = String.Empty;
573 string lang = String.Empty;
574 string password = String.Empty;
575 string errormessages = String.Empty;
576
577 // the client requires the HTML form field be named 'username'
578 // however, the data it sends when it loads the first time is 'firstname'
579 // another one of those little nuances.
580
581 if (keysvals.Contains("firstname"))
582 firstname = wfcut.Replace((string)keysvals["firstname"], String.Empty, 99999);
583
584 if (keysvals.Contains("username"))
585 firstname = wfcut.Replace((string)keysvals["username"], String.Empty, 99999);
586
587 if (keysvals.Contains("lastname"))
588 lastname = wfcut.Replace((string)keysvals["lastname"], String.Empty, 99999);
589
590 if (keysvals.Contains("location"))
591 location = wfcut.Replace((string)keysvals["location"], String.Empty, 99999);
592
593 if (keysvals.Contains("region"))
594 region = wfcut.Replace((string)keysvals["region"], String.Empty, 99999);
595
596 if (keysvals.Contains("grid"))
597 grid = wfcut.Replace((string)keysvals["grid"], String.Empty, 99999);
598
599 if (keysvals.Contains("channel"))
600 channel = wfcut.Replace((string)keysvals["channel"], String.Empty, 99999);
601
602 if (keysvals.Contains("version"))
603 version = wfcut.Replace((string)keysvals["version"], String.Empty, 99999);
604
605 if (keysvals.Contains("lang"))
606 lang = wfcut.Replace((string)keysvals["lang"], String.Empty, 99999);
607
608 if (keysvals.Contains("password"))
609 password = wfcut.Replace((string)keysvals["password"], String.Empty, 99999);
610
611 // load our login form.
612 string loginform = GetLoginForm(firstname, lastname, location, region, grid, channel, version, lang, password, errormessages);
613
614 if (keysvals.ContainsKey("show_login_form"))
615 {
616 UserProfileData user = GetTheUser(firstname, lastname);
617 bool goodweblogin = false;
618
619 if (user != null)
620 goodweblogin = AuthenticateUser(user, password);
621
622 if (goodweblogin)
623 {
624 UUID webloginkey = UUID.Random();
625 m_userManager.StoreWebLoginKey(user.ID, webloginkey);
626 //statuscode = 301;
627
628 // string redirectURL = "about:blank?redirect-http-hack=" +
629 // HttpUtility.UrlEncode("secondlife:///app/login?first_name=" + firstname + "&last_name=" +
630 // lastname +
631 // "&location=" + location + "&grid=Other&web_login_key=" + webloginkey.ToString());
632 //m_log.Info("[WEB]: R:" + redirectURL);
633 returnactions["int_response_code"] = statuscode;
634 //returnactions["str_redirect_location"] = redirectURL;
635 //returnactions["str_response_string"] = "<HTML><BODY>GoodLogin</BODY></HTML>";
636 returnactions["str_response_string"] = webloginkey.ToString();
637 }
638 else
639 {
640 errormessages = "The Username and password supplied did not match our records. Check your caps lock and try again";
641
642 loginform = GetLoginForm(firstname, lastname, location, region, grid, channel, version, lang, password, errormessages);
643 returnactions["int_response_code"] = statuscode;
644 returnactions["str_response_string"] = loginform;
645 }
646 }
647 else
648 {
649 returnactions["int_response_code"] = statuscode;
650 returnactions["str_response_string"] = loginform;
651 }
652 return returnactions;
653 }
654
655 public string GetLoginForm(string firstname, string lastname, string location, string region,
656 string grid, string channel, string version, string lang,
657 string password, string errormessages)
658 {
659 // inject our values in the form at the markers
660
661 string loginform = String.Empty;
662 string file = Path.Combine(Util.configDir(), "http_loginform.html");
663 if (!File.Exists(file))
664 {
665 loginform = GetDefaultLoginForm();
666 }
667 else
668 {
669 StreamReader sr = File.OpenText(file);
670 loginform = sr.ReadToEnd();
671 sr.Close();
672 }
673
674 loginform = loginform.Replace("[$firstname]", firstname);
675 loginform = loginform.Replace("[$lastname]", lastname);
676 loginform = loginform.Replace("[$location]", location);
677 loginform = loginform.Replace("[$region]", region);
678 loginform = loginform.Replace("[$grid]", grid);
679 loginform = loginform.Replace("[$channel]", channel);
680 loginform = loginform.Replace("[$version]", version);
681 loginform = loginform.Replace("[$lang]", lang);
682 loginform = loginform.Replace("[$password]", password);
683 loginform = loginform.Replace("[$errors]", errormessages);
684
685 return loginform;
686 }
687
688 public string GetDefaultLoginForm()
689 {
690 string responseString =
691 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
692 responseString += "<html xmlns=\"http://www.w3.org/1999/xhtml\">";
693 responseString += "<head>";
694 responseString += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />";
695 responseString += "<meta http-equiv=\"cache-control\" content=\"no-cache\">";
696 responseString += "<meta http-equiv=\"Pragma\" content=\"no-cache\">";
697 responseString += "<title>OpenSim Login</title>";
698 responseString += "<body><br />";
699 responseString += "<div id=\"login_box\">";
700
701 responseString += "<form action=\"/go.cgi\" method=\"GET\" id=\"login-form\">";
702
703 responseString += "<div id=\"message\">[$errors]</div>";
704 responseString += "<fieldset id=\"firstname\">";
705 responseString += "<legend>First Name:</legend>";
706 responseString += "<input type=\"text\" id=\"firstname_input\" size=\"15\" maxlength=\"100\" name=\"username\" value=\"[$firstname]\" />";
707 responseString += "</fieldset>";
708 responseString += "<fieldset id=\"lastname\">";
709 responseString += "<legend>Last Name:</legend>";
710 responseString += "<input type=\"text\" size=\"15\" maxlength=\"100\" name=\"lastname\" value=\"[$lastname]\" />";
711 responseString += "</fieldset>";
712 responseString += "<fieldset id=\"password\">";
713 responseString += "<legend>Password:</legend>";
714 responseString += "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">";
715 responseString += "<tr>";
716 responseString += "<td colspan=\"2\"><input type=\"password\" size=\"15\" maxlength=\"100\" name=\"password\" value=\"[$password]\" /></td>";
717 responseString += "</tr>";
718 responseString += "<tr>";
719 responseString += "<td valign=\"middle\"><input type=\"checkbox\" name=\"remember_password\" id=\"remember_password\" [$remember_password] style=\"margin-left:0px;\"/></td>";
720 responseString += "<td><label for=\"remember_password\">Remember password</label></td>";
721 responseString += "</tr>";
722 responseString += "</table>";
723 responseString += "</fieldset>";
724 responseString += "<input type=\"hidden\" name=\"show_login_form\" value=\"FALSE\" />";
725 responseString += "<input type=\"hidden\" name=\"method\" value=\"login\" />";
726 responseString += "<input type=\"hidden\" id=\"grid\" name=\"grid\" value=\"[$grid]\" />";
727 responseString += "<input type=\"hidden\" id=\"region\" name=\"region\" value=\"[$region]\" />";
728 responseString += "<input type=\"hidden\" id=\"location\" name=\"location\" value=\"[$location]\" />";
729 responseString += "<input type=\"hidden\" id=\"channel\" name=\"channel\" value=\"[$channel]\" />";
730 responseString += "<input type=\"hidden\" id=\"version\" name=\"version\" value=\"[$version]\" />";
731 responseString += "<input type=\"hidden\" id=\"lang\" name=\"lang\" value=\"[$lang]\" />";
732 responseString += "<div id=\"submitbtn\">";
733 responseString += "<input class=\"input_over\" type=\"submit\" value=\"Connect\" />";
734 responseString += "</div>";
735 responseString += "<div id=\"connecting\" style=\"visibility:hidden\"> Connecting...</div>";
736
737 responseString += "<div id=\"helplinks\"><!---";
738 responseString += "<a href=\"#join now link\" target=\"_blank\"></a> | ";
739 responseString += "<a href=\"#forgot password link\" target=\"_blank\"></a>";
740 responseString += "---></div>";
741
742 responseString += "<div id=\"channelinfo\"> [$channel] | [$version]=[$lang]</div>";
743 responseString += "</form>";
744 responseString += "<script language=\"JavaScript\">";
745 responseString += "document.getElementById('firstname_input').focus();";
746 responseString += "</script>";
747 responseString += "</div>";
748 responseString += "</div>";
749 responseString += "</body>";
750 responseString += "</html>";
751
752 return responseString;
753 }
754
755 /// <summary>
756 /// Saves a target agent to the database
757 /// </summary>
758 /// <param name="profile">The users profile</param>
759 /// <returns>Successful?</returns>
760 public bool CommitAgent(ref UserProfileData profile)
761 {
762 return m_userManager.CommitAgent(ref profile);
763 }
764
765 /// <summary>
766 /// Checks a user against it's password hash
767 /// </summary>
768 /// <param name="profile">The users profile</param>
769 /// <param name="password">The supplied password</param>
770 /// <returns>Authenticated?</returns>
771 public virtual bool AuthenticateUser(UserProfileData profile, string password)
772 {
773 bool passwordSuccess = false;
774 //m_log.InfoFormat("[LOGIN]: Authenticating {0} {1} ({2})", profile.FirstName, profile.SurName, profile.ID);
775
776 // Web Login method seems to also occasionally send the hashed password itself
777
778 // we do this to get our hash in a form that the server password code can consume
779 // when the web-login-form submits the password in the clear (supposed to be over SSL!)
780 if (!password.StartsWith("$1$"))
781 password = "$1$" + Util.Md5Hash(password);
782
783 password = password.Remove(0, 3); //remove $1$
784
785 string s = Util.Md5Hash(password + ":" + profile.PasswordSalt);
786 // Testing...
787 //m_log.Info("[LOGIN]: SubHash:" + s + " userprofile:" + profile.passwordHash);
788 //m_log.Info("[LOGIN]: userprofile:" + profile.passwordHash + " SubCT:" + password);
789
790 passwordSuccess = (profile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
791 || profile.PasswordHash.Equals(password, StringComparison.InvariantCulture));
792
793 return passwordSuccess;
794 }
795
796 public virtual bool AuthenticateUser(UserProfileData profile, UUID webloginkey)
797 {
798 bool passwordSuccess = false;
799 m_log.InfoFormat("[LOGIN]: Authenticating {0} {1} ({2})", profile.FirstName, profile.SurName, profile.ID);
800
801 // Match web login key unless it's the default weblogin key UUID.Zero
802 passwordSuccess = ((profile.WebLoginKey == webloginkey) && profile.WebLoginKey != UUID.Zero);
803
804 return passwordSuccess;
805 }
806
807 /// <summary>
808 ///
809 /// </summary>
810 /// <param name="profile"></param>
811 /// <param name="request"></param>
812 public void CreateAgent(UserProfileData profile, XmlRpcRequest request)
813 {
814 m_userManager.CreateAgent(profile, request);
815 }
816
817 public void CreateAgent(UserProfileData profile, OSD request)
818 {
819 m_userManager.CreateAgent(profile, request);
820 }
821
822 /// <summary>
823 ///
824 /// </summary>
825 /// <param name="firstname"></param>
826 /// <param name="lastname"></param>
827 /// <returns></returns>
828 public virtual UserProfileData GetTheUser(string firstname, string lastname)
829 {
830 return m_userManager.GetUserProfile(firstname, lastname);
831 }
832
833 /// <summary>
834 ///
835 /// </summary>
836 /// <returns></returns>
837 public virtual string GetMessage()
838 {
839 return m_welcomeMessage;
840 }
841
842 private static LoginResponse.BuddyList ConvertFriendListItem(List<FriendListItem> LFL)
843 {
844 LoginResponse.BuddyList buddylistreturn = new LoginResponse.BuddyList();
845 foreach (FriendListItem fl in LFL)
846 {
847 LoginResponse.BuddyList.BuddyInfo buddyitem = new LoginResponse.BuddyList.BuddyInfo(fl.Friend);
848 buddyitem.BuddyID = fl.Friend;
849 buddyitem.BuddyRightsHave = (int)fl.FriendListOwnerPerms;
850 buddyitem.BuddyRightsGiven = (int)fl.FriendPerms;
851 buddylistreturn.AddNewBuddy(buddyitem);
852 }
853 return buddylistreturn;
854 }
855
856 /// <summary>
857 /// Converts the inventory library skeleton into the form required by the rpc request.
858 /// </summary>
859 /// <returns></returns>
860 protected virtual ArrayList GetInventoryLibrary()
861 {
862 Dictionary<UUID, InventoryFolderImpl> rootFolders
863 = m_libraryRootFolder.RequestSelfAndDescendentFolders();
864 ArrayList folderHashes = new ArrayList();
865
866 foreach (InventoryFolderBase folder in rootFolders.Values)
867 {
868 Hashtable TempHash = new Hashtable();
869 TempHash["name"] = folder.Name;
870 TempHash["parent_id"] = folder.ParentID.ToString();
871 TempHash["version"] = (Int32)folder.Version;
872 TempHash["type_default"] = (Int32)folder.Type;
873 TempHash["folder_id"] = folder.ID.ToString();
874 folderHashes.Add(TempHash);
875 }
876
877 return folderHashes;
878 }
879
880 /// <summary>
881 ///
882 /// </summary>
883 /// <returns></returns>
884 protected virtual ArrayList GetLibraryOwner()
885 {
886 //for now create random inventory library owner
887 Hashtable TempHash = new Hashtable();
888 TempHash["agent_id"] = "11111111-1111-0000-0000-000100bba000";
889 ArrayList inventoryLibOwner = new ArrayList();
890 inventoryLibOwner.Add(TempHash);
891 return inventoryLibOwner;
892 }
893
894 public class InventoryData
895 {
896 public ArrayList InventoryArray = null;
897 public UUID RootFolderID = UUID.Zero;
898
899 public InventoryData(ArrayList invList, UUID rootID)
900 {
901 InventoryArray = invList;
902 RootFolderID = rootID;
903 }
904 }
905
906 protected void SniffLoginKey(Uri uri, Hashtable requestData)
907 {
908 string uri_str = uri.ToString();
909 string[] parts = uri_str.Split(new char[] { '=' });
910 if (parts.Length > 1)
911 {
912 string web_login_key = parts[1];
913 requestData.Add("web_login_key", web_login_key);
914 m_log.InfoFormat("[LOGIN]: Login with web_login_key {0}", web_login_key);
915 }
916 }
917
918 /// <summary>
919 /// Customises the login response and fills in missing values. This method also tells the login region to
920 /// expect a client connection.
921 /// </summary>
922 /// <param name="response">The existing response</param>
923 /// <param name="theUser">The user profile</param>
924 /// <param name="startLocationRequest">The requested start location</param>
925 /// <returns>true on success, false if the region was not successfully told to expect a user connection</returns>
926 public bool CustomiseResponse(LoginResponse response, UserProfileData theUser, string startLocationRequest, IPEndPoint client)
927 {
928 // add active gestures to login-response
929 AddActiveGestures(response, theUser);
930
931 // HomeLocation
932 RegionInfo homeInfo = null;
933
934 // use the homeRegionID if it is stored already. If not, use the regionHandle as before
935 UUID homeRegionId = theUser.HomeRegionID;
936 ulong homeRegionHandle = theUser.HomeRegion;
937 if (homeRegionId != UUID.Zero)
938 {
939 homeInfo = GetRegionInfo(homeRegionId);
940 }
941 else
942 {
943 homeInfo = GetRegionInfo(homeRegionHandle);
944 }
945
946 if (homeInfo != null)
947 {
948 response.Home =
949 string.Format(
950 "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}",
951 (homeInfo.RegionLocX * Constants.RegionSize),
952 (homeInfo.RegionLocY * Constants.RegionSize),
953 theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z,
954 theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z);
955 }
956 else
957 {
958 m_log.InfoFormat("not found the region at {0} {1}", theUser.HomeRegionX, theUser.HomeRegionY);
959 // Emergency mode: Home-region isn't available, so we can't request the region info.
960 // Use the stored home regionHandle instead.
961 // NOTE: If the home-region moves, this will be wrong until the users update their user-profile again
962 ulong regionX = homeRegionHandle >> 32;
963 ulong regionY = homeRegionHandle & 0xffffffff;
964 response.Home =
965 string.Format(
966 "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}",
967 regionX, regionY,
968 theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z,
969 theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z);
970
971 m_log.InfoFormat("[LOGIN] Home region of user {0} {1} is not available; using computed region position {2} {3}",
972 theUser.FirstName, theUser.SurName,
973 regionX, regionY);
974 }
975
976 // StartLocation
977 RegionInfo regionInfo = null;
978 if (startLocationRequest == "home")
979 {
980 regionInfo = homeInfo;
981 theUser.CurrentAgent.Position = theUser.HomeLocation;
982 response.LookAt = String.Format("[r{0},r{1},r{2}]", theUser.HomeLookAt.X.ToString(),
983 theUser.HomeLookAt.Y.ToString(), theUser.HomeLookAt.Z.ToString());
984 }
985 else if (startLocationRequest == "last")
986 {
987 UUID lastRegion = theUser.CurrentAgent.Region;
988 regionInfo = GetRegionInfo(lastRegion);
989 response.LookAt = String.Format("[r{0},r{1},r{2}]", theUser.CurrentAgent.LookAt.X.ToString(),
990 theUser.CurrentAgent.LookAt.Y.ToString(), theUser.CurrentAgent.LookAt.Z.ToString());
991 }
992 else
993 {
994 Regex reURI = new Regex(@"^uri:(?<region>[^&]+)&(?<x>\d+)&(?<y>\d+)&(?<z>\d+)$");
995 Match uriMatch = reURI.Match(startLocationRequest);
996 if (uriMatch == null)
997 {
998 m_log.InfoFormat("[LOGIN]: Got Custom Login URL {0}, but can't process it", startLocationRequest);
999 }
1000 else
1001 {
1002 string region = uriMatch.Groups["region"].ToString();
1003 regionInfo = RequestClosestRegion(region);
1004 if (regionInfo == null)
1005 {
1006 m_log.InfoFormat("[LOGIN]: Got Custom Login URL {0}, can't locate region {1}", startLocationRequest, region);
1007 }
1008 else
1009 {
1010 theUser.CurrentAgent.Position = new Vector3(float.Parse(uriMatch.Groups["x"].Value, Culture.NumberFormatInfo),
1011 float.Parse(uriMatch.Groups["y"].Value, Culture.NumberFormatInfo), float.Parse(uriMatch.Groups["z"].Value, Culture.NumberFormatInfo));
1012 }
1013 }
1014 response.LookAt = "[r0,r1,r0]";
1015 // can be: last, home, safe, url
1016 response.StartLocation = "url";
1017 }
1018
1019 if ((regionInfo != null) && (PrepareLoginToRegion(regionInfo, theUser, response, client)))
1020 {
1021 return true;
1022 }
1023
1024 // Get the default region handle
1025 ulong defaultHandle = Utils.UIntsToLong(m_defaultHomeX * Constants.RegionSize, m_defaultHomeY * Constants.RegionSize);
1026
1027 // If we haven't already tried the default region, reset regionInfo
1028 if (regionInfo != null && defaultHandle != regionInfo.RegionHandle)
1029 regionInfo = null;
1030
1031 if (regionInfo == null)
1032 {
1033 m_log.Error("[LOGIN]: Sending user to default region " + defaultHandle + " instead");
1034 regionInfo = GetRegionInfo(defaultHandle);
1035 }
1036
1037 if (regionInfo == null)
1038 {
1039 m_log.ErrorFormat("[LOGIN]: Sending user to any region");
1040 regionInfo = RequestClosestRegion(String.Empty);
1041 }
1042
1043 theUser.CurrentAgent.Position = new Vector3(128f, 128f, 0f);
1044 response.StartLocation = "safe";
1045
1046 return PrepareLoginToRegion(regionInfo, theUser, response, client);
1047 }
1048
1049 protected abstract RegionInfo RequestClosestRegion(string region);
1050 protected abstract RegionInfo GetRegionInfo(ulong homeRegionHandle);
1051 protected abstract RegionInfo GetRegionInfo(UUID homeRegionId);
1052
1053 /// <summary>
1054 /// If the user is already logged in, try to notify the region that the user they've got is dead.
1055 /// </summary>
1056 /// <param name="theUser"></param>
1057 public abstract void LogOffUser(UserProfileData theUser, string message);
1058
1059 /// <summary>
1060 /// Prepare a login to the given region. This involves both telling the region to expect a connection
1061 /// and appropriately customising the response to the user.
1062 /// </summary>
1063 /// <param name="sim"></param>
1064 /// <param name="user"></param>
1065 /// <param name="response"></param>
1066 /// <param name="remoteClient"></param>
1067 /// <returns>true if the region was successfully contacted, false otherwise</returns>
1068 protected abstract bool PrepareLoginToRegion(
1069 RegionInfo regionInfo, UserProfileData user, LoginResponse response, IPEndPoint client);
1070
1071 /// <summary>
1072 /// Add active gestures of the user to the login response.
1073 /// </summary>
1074 /// <param name="response">
1075 /// A <see cref="LoginResponse"/>
1076 /// </param>
1077 /// <param name="theUser">
1078 /// A <see cref="UserProfileData"/>
1079 /// </param>
1080 protected void AddActiveGestures(LoginResponse response, UserProfileData theUser)
1081 {
1082 List<InventoryItemBase> gestures = null;
1083 try
1084 {
1085 if (m_InventoryService != null)
1086 gestures = m_InventoryService.GetActiveGestures(theUser.ID);
1087 else
1088 gestures = m_interInventoryService.GetActiveGestures(theUser.ID);
1089 }
1090 catch (Exception e)
1091 {
1092 m_log.Debug("[LOGIN]: Unable to retrieve active gestures from inventory server. Reason: " + e.Message);
1093 }
1094 //m_log.DebugFormat("[LOGIN]: AddActiveGestures, found {0}", gestures == null ? 0 : gestures.Count);
1095 ArrayList list = new ArrayList();
1096 if (gestures != null)
1097 {
1098 foreach (InventoryItemBase gesture in gestures)
1099 {
1100 Hashtable item = new Hashtable();
1101 item["item_id"] = gesture.ID.ToString();
1102 item["asset_id"] = gesture.AssetID.ToString();
1103 list.Add(item);
1104 }
1105 }
1106 response.ActiveGestures = list;
1107 }
1108
1109 /// <summary>
1110 /// Get the initial login inventory skeleton (in other words, the folder structure) for the given user.
1111 /// </summary>
1112 /// <param name="userID"></param>
1113 /// <returns></returns>
1114 /// <exception cref='System.Exception'>This will be thrown if there is a problem with the inventory service</exception>
1115 protected InventoryData GetInventorySkeleton(UUID userID)
1116 {
1117 List<InventoryFolderBase> folders = null;
1118 if (m_InventoryService != null)
1119 {
1120 folders = m_InventoryService.GetInventorySkeleton(userID);
1121 }
1122 else
1123 {
1124 folders = m_interInventoryService.GetInventorySkeleton(userID);
1125 }
1126
1127 // If we have user auth but no inventory folders for some reason, create a new set of folders.
1128 if (folders == null || folders.Count == 0)
1129 {
1130 m_log.InfoFormat(
1131 "[LOGIN]: A root inventory folder for user {0} was not found. Requesting creation.", userID);
1132
1133 // Although the create user function creates a new agent inventory along with a new user profile, some
1134 // tools are creating the user profile directly in the database without creating the inventory. At
1135 // this time we'll accomodate them by lazily creating the user inventory now if it doesn't already
1136 // exist.
1137 if (m_interInventoryService != null)
1138 {
1139 if (!m_interInventoryService.CreateNewUserInventory(userID))
1140 {
1141 throw new Exception(
1142 String.Format(
1143 "The inventory creation request for user {0} did not succeed."
1144 + " Please contact your inventory service provider for more information.",
1145 userID));
1146 }
1147 }
1148 else if ((m_InventoryService != null) && !m_InventoryService.CreateUserInventory(userID))
1149 {
1150 throw new Exception(
1151 String.Format(
1152 "The inventory creation request for user {0} did not succeed."
1153 + " Please contact your inventory service provider for more information.",
1154 userID));
1155 }
1156
1157
1158 m_log.InfoFormat("[LOGIN]: A new inventory skeleton was successfully created for user {0}", userID);
1159
1160 if (m_InventoryService != null)
1161 folders = m_InventoryService.GetInventorySkeleton(userID);
1162 else
1163 folders = m_interInventoryService.GetInventorySkeleton(userID);
1164
1165 if (folders == null || folders.Count == 0)
1166 {
1167 throw new Exception(
1168 String.Format(
1169 "A root inventory folder for user {0} could not be retrieved from the inventory service",
1170 userID));
1171 }
1172 }
1173
1174 UUID rootID = UUID.Zero;
1175 ArrayList AgentInventoryArray = new ArrayList();
1176 Hashtable TempHash;
1177 foreach (InventoryFolderBase InvFolder in folders)
1178 {
1179 if (InvFolder.ParentID == UUID.Zero)
1180 {
1181 rootID = InvFolder.ID;
1182 }
1183 TempHash = new Hashtable();
1184 TempHash["name"] = InvFolder.Name;
1185 TempHash["parent_id"] = InvFolder.ParentID.ToString();
1186 TempHash["version"] = (Int32)InvFolder.Version;
1187 TempHash["type_default"] = (Int32)InvFolder.Type;
1188 TempHash["folder_id"] = InvFolder.ID.ToString();
1189 AgentInventoryArray.Add(TempHash);
1190 }
1191
1192 return new InventoryData(AgentInventoryArray, rootID);
1193 }
1194
1195 protected virtual bool AllowLoginWithoutInventory()
1196 {
1197 return false;
1198 }
1199
1200 public XmlRpcResponse XmlRPCCheckAuthSession(XmlRpcRequest request, IPEndPoint remoteClient)
1201 {
1202 XmlRpcResponse response = new XmlRpcResponse();
1203 Hashtable requestData = (Hashtable)request.Params[0];
1204
1205 string authed = "FALSE";
1206 if (requestData.Contains("avatar_uuid") && requestData.Contains("session_id"))
1207 {
1208 UUID guess_aid;
1209 UUID guess_sid;
1210
1211 UUID.TryParse((string)requestData["avatar_uuid"], out guess_aid);
1212 if (guess_aid == UUID.Zero)
1213 {
1214 return Util.CreateUnknownUserErrorResponse();
1215 }
1216
1217 UUID.TryParse((string)requestData["session_id"], out guess_sid);
1218 if (guess_sid == UUID.Zero)
1219 {
1220 return Util.CreateUnknownUserErrorResponse();
1221 }
1222
1223 if (m_userManager.VerifySession(guess_aid, guess_sid))
1224 {
1225 authed = "TRUE";
1226 m_log.InfoFormat("[UserManager]: CheckAuthSession TRUE for user {0}", guess_aid);
1227 }
1228 else
1229 {
1230 m_log.InfoFormat("[UserManager]: CheckAuthSession FALSE");
1231 return Util.CreateUnknownUserErrorResponse();
1232 }
1233 }
1234
1235 Hashtable responseData = new Hashtable();
1236 responseData["auth_session"] = authed;
1237 response.Value = responseData;
1238 return response;
1239 }
1240 }
1241} \ No newline at end of file