diff options
Diffstat (limited to 'OpenSim/Services/LLLoginService/LLLoginService.cs')
-rw-r--r-- | OpenSim/Services/LLLoginService/LLLoginService.cs | 1180 |
1 files changed, 1180 insertions, 0 deletions
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs new file mode 100644 index 0000000..cad0988 --- /dev/null +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs | |||
@@ -0,0 +1,1180 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Linq; | ||
32 | using System.Net; | ||
33 | using System.Reflection; | ||
34 | using System.Text.RegularExpressions; | ||
35 | |||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using OpenMetaverse; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Console; | ||
42 | using OpenSim.Server.Base; | ||
43 | using OpenSim.Services.Connectors.InstantMessage; | ||
44 | using OpenSim.Services.Interfaces; | ||
45 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
46 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
47 | using OpenSim.Services.Connectors.Hypergrid; | ||
48 | |||
49 | namespace OpenSim.Services.LLLoginService | ||
50 | { | ||
51 | public class LLLoginService : ILoginService | ||
52 | { | ||
53 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
54 | private static readonly string LogHeader = "[LLOGIN SERVICE]"; | ||
55 | |||
56 | private static bool Initialized = false; | ||
57 | |||
58 | protected IUserAccountService m_UserAccountService; | ||
59 | protected IGridUserService m_GridUserService; | ||
60 | protected IAuthenticationService m_AuthenticationService; | ||
61 | protected IInventoryService m_InventoryService; | ||
62 | protected IInventoryService m_HGInventoryService; | ||
63 | protected IGridService m_GridService; | ||
64 | protected IPresenceService m_PresenceService; | ||
65 | protected ISimulationService m_LocalSimulationService; | ||
66 | protected ISimulationService m_RemoteSimulationService; | ||
67 | protected ILibraryService m_LibraryService; | ||
68 | protected IFriendsService m_FriendsService; | ||
69 | protected IAvatarService m_AvatarService; | ||
70 | protected IUserAgentService m_UserAgentService; | ||
71 | |||
72 | protected GatekeeperServiceConnector m_GatekeeperConnector; | ||
73 | |||
74 | protected string m_DefaultRegionName; | ||
75 | protected string m_WelcomeMessage; | ||
76 | protected bool m_RequireInventory; | ||
77 | protected int m_MinLoginLevel; | ||
78 | protected string m_GatekeeperURL; | ||
79 | protected bool m_AllowRemoteSetLoginLevel; | ||
80 | protected string m_MapTileURL; | ||
81 | protected string m_ProfileURL; | ||
82 | protected string m_OpenIDURL; | ||
83 | protected string m_SearchURL; | ||
84 | protected string m_Currency; | ||
85 | protected string m_ClassifiedFee; | ||
86 | protected int m_MaxAgentGroups = 42; | ||
87 | protected string m_DestinationGuide; | ||
88 | protected string m_AvatarPicker; | ||
89 | protected string m_AllowedClients; | ||
90 | protected string m_DeniedClients; | ||
91 | protected string m_MessageUrl; | ||
92 | protected string m_DSTZone; | ||
93 | protected bool m_allowDuplicatePresences = false; | ||
94 | |||
95 | IConfig m_LoginServerConfig; | ||
96 | // IConfig m_ClientsConfig; | ||
97 | |||
98 | public LLLoginService(IConfigSource config, ISimulationService simService, ILibraryService libraryService) | ||
99 | { | ||
100 | m_LoginServerConfig = config.Configs["LoginService"]; | ||
101 | if (m_LoginServerConfig == null) | ||
102 | throw new Exception(String.Format("No section LoginService in config file")); | ||
103 | |||
104 | string accountService = m_LoginServerConfig.GetString("UserAccountService", String.Empty); | ||
105 | string gridUserService = m_LoginServerConfig.GetString("GridUserService", String.Empty); | ||
106 | string agentService = m_LoginServerConfig.GetString("UserAgentService", String.Empty); | ||
107 | string authService = m_LoginServerConfig.GetString("AuthenticationService", String.Empty); | ||
108 | string invService = m_LoginServerConfig.GetString("InventoryService", String.Empty); | ||
109 | string gridService = m_LoginServerConfig.GetString("GridService", String.Empty); | ||
110 | string presenceService = m_LoginServerConfig.GetString("PresenceService", String.Empty); | ||
111 | string libService = m_LoginServerConfig.GetString("LibraryService", String.Empty); | ||
112 | string friendsService = m_LoginServerConfig.GetString("FriendsService", String.Empty); | ||
113 | string avatarService = m_LoginServerConfig.GetString("AvatarService", String.Empty); | ||
114 | string simulationService = m_LoginServerConfig.GetString("SimulationService", String.Empty); | ||
115 | |||
116 | m_DefaultRegionName = m_LoginServerConfig.GetString("DefaultRegion", String.Empty); | ||
117 | m_WelcomeMessage = m_LoginServerConfig.GetString("WelcomeMessage", "Welcome to OpenSim!"); | ||
118 | m_RequireInventory = m_LoginServerConfig.GetBoolean("RequireInventory", true); | ||
119 | m_AllowRemoteSetLoginLevel = m_LoginServerConfig.GetBoolean("AllowRemoteSetLoginLevel", false); | ||
120 | m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0); | ||
121 | m_GatekeeperURL = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI", | ||
122 | new string[] { "Startup", "Hypergrid", "LoginService" }, String.Empty); | ||
123 | m_MapTileURL = m_LoginServerConfig.GetString("MapTileURL", string.Empty); | ||
124 | m_ProfileURL = m_LoginServerConfig.GetString("ProfileServerURL", string.Empty); | ||
125 | m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty); | ||
126 | m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty); | ||
127 | m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty); | ||
128 | m_ClassifiedFee = m_LoginServerConfig.GetString("ClassifiedFee", string.Empty); | ||
129 | m_DestinationGuide = m_LoginServerConfig.GetString ("DestinationGuide", string.Empty); | ||
130 | m_AvatarPicker = m_LoginServerConfig.GetString ("AvatarPicker", string.Empty); | ||
131 | |||
132 | string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "LoginService" }; | ||
133 | m_AllowedClients = Util.GetConfigVarFromSections<string>( | ||
134 | config, "AllowedClients", possibleAccessControlConfigSections, string.Empty); | ||
135 | m_DeniedClients = Util.GetConfigVarFromSections<string>( | ||
136 | config, "DeniedClients", possibleAccessControlConfigSections, string.Empty); | ||
137 | |||
138 | m_MessageUrl = m_LoginServerConfig.GetString("MessageUrl", string.Empty); | ||
139 | m_DSTZone = m_LoginServerConfig.GetString("DSTZone", "America/Los_Angeles;Pacific Standard Time"); | ||
140 | |||
141 | IConfig groupConfig = config.Configs["Groups"]; | ||
142 | if (groupConfig != null) | ||
143 | m_MaxAgentGroups = groupConfig.GetInt("MaxAgentGroups", 42); | ||
144 | |||
145 | IConfig presenceConfig = config.Configs["PresenceService"]; | ||
146 | if (presenceConfig != null) | ||
147 | { | ||
148 | m_allowDuplicatePresences = presenceConfig.GetBoolean("AllowDuplicatePresences", m_allowDuplicatePresences); | ||
149 | } | ||
150 | |||
151 | // Clean up some of these vars | ||
152 | if (m_MapTileURL != String.Empty) | ||
153 | { | ||
154 | m_MapTileURL = m_MapTileURL.Trim(); | ||
155 | if (!m_MapTileURL.EndsWith("/")) | ||
156 | m_MapTileURL = m_MapTileURL + "/"; | ||
157 | } | ||
158 | |||
159 | // These are required; the others aren't | ||
160 | if (accountService == string.Empty || authService == string.Empty) | ||
161 | throw new Exception("LoginService is missing service specifications"); | ||
162 | |||
163 | // replace newlines in welcome message | ||
164 | m_WelcomeMessage = m_WelcomeMessage.Replace("\\n", "\n"); | ||
165 | |||
166 | Object[] args = new Object[] { config }; | ||
167 | m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args); | ||
168 | m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args); | ||
169 | Object[] authArgs = new Object[] { config, m_UserAccountService }; | ||
170 | m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, authArgs); | ||
171 | m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args); | ||
172 | |||
173 | if (gridService != string.Empty) | ||
174 | m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); | ||
175 | if (presenceService != string.Empty) | ||
176 | m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); | ||
177 | if (avatarService != string.Empty) | ||
178 | m_AvatarService = ServerUtils.LoadPlugin<IAvatarService>(avatarService, args); | ||
179 | if (friendsService != string.Empty) | ||
180 | m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(friendsService, args); | ||
181 | if (simulationService != string.Empty) | ||
182 | m_RemoteSimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args); | ||
183 | if (agentService != string.Empty) | ||
184 | m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(agentService, args); | ||
185 | |||
186 | // Get the Hypergrid inventory service (exists only if Hypergrid is enabled) | ||
187 | string hgInvServicePlugin = m_LoginServerConfig.GetString("HGInventoryServicePlugin", String.Empty); | ||
188 | if (hgInvServicePlugin != string.Empty) | ||
189 | { | ||
190 | // TODO: Remove HGInventoryServiceConstructorArg after 0.9 release | ||
191 | string hgInvServiceArg = m_LoginServerConfig.GetString("HGInventoryServiceConstructorArg", String.Empty); | ||
192 | if (hgInvServiceArg != String.Empty) | ||
193 | { | ||
194 | m_log.Warn("[LLOGIN SERVICE]: You are using HGInventoryServiceConstructorArg, which is deprecated. See example file for correct syntax."); | ||
195 | hgInvServicePlugin = hgInvServiceArg + "@" + hgInvServicePlugin; | ||
196 | } | ||
197 | m_HGInventoryService = ServerUtils.LoadPlugin<IInventoryService>(hgInvServicePlugin, args); | ||
198 | } | ||
199 | |||
200 | // | ||
201 | // deal with the services given as argument | ||
202 | // | ||
203 | m_LocalSimulationService = simService; | ||
204 | if (libraryService != null) | ||
205 | { | ||
206 | m_log.DebugFormat("[LLOGIN SERVICE]: Using LibraryService given as argument"); | ||
207 | m_LibraryService = libraryService; | ||
208 | } | ||
209 | else if (libService != string.Empty) | ||
210 | { | ||
211 | m_log.DebugFormat("[LLOGIN SERVICE]: Using instantiated LibraryService"); | ||
212 | m_LibraryService = ServerUtils.LoadPlugin<ILibraryService>(libService, args); | ||
213 | } | ||
214 | |||
215 | m_GatekeeperConnector = new GatekeeperServiceConnector(); | ||
216 | |||
217 | if (!Initialized) | ||
218 | { | ||
219 | Initialized = true; | ||
220 | RegisterCommands(); | ||
221 | } | ||
222 | |||
223 | m_log.DebugFormat("[LLOGIN SERVICE]: Starting..."); | ||
224 | |||
225 | } | ||
226 | |||
227 | public LLLoginService(IConfigSource config) : this(config, null, null) | ||
228 | { | ||
229 | } | ||
230 | |||
231 | public Hashtable SetLevel(string firstName, string lastName, string passwd, int level, IPEndPoint clientIP) | ||
232 | { | ||
233 | Hashtable response = new Hashtable(); | ||
234 | response["success"] = "false"; | ||
235 | |||
236 | if (!m_AllowRemoteSetLoginLevel) | ||
237 | return response; | ||
238 | |||
239 | try | ||
240 | { | ||
241 | UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, firstName, lastName); | ||
242 | if (account == null) | ||
243 | { | ||
244 | m_log.InfoFormat("[LLOGIN SERVICE]: Set Level failed, user {0} {1} not found", firstName, lastName); | ||
245 | return response; | ||
246 | } | ||
247 | |||
248 | if (account.UserLevel < 200) | ||
249 | { | ||
250 | m_log.InfoFormat("[LLOGIN SERVICE]: Set Level failed, reason: user level too low"); | ||
251 | return response; | ||
252 | } | ||
253 | |||
254 | // | ||
255 | // Authenticate this user | ||
256 | // | ||
257 | // We don't support clear passwords here | ||
258 | // | ||
259 | string token = m_AuthenticationService.Authenticate(account.PrincipalID, passwd, 30); | ||
260 | UUID secureSession = UUID.Zero; | ||
261 | if ((token == string.Empty) || (token != string.Empty && !UUID.TryParse(token, out secureSession))) | ||
262 | { | ||
263 | m_log.InfoFormat("[LLOGIN SERVICE]: SetLevel failed, reason: authentication failed"); | ||
264 | return response; | ||
265 | } | ||
266 | } | ||
267 | catch (Exception e) | ||
268 | { | ||
269 | m_log.Error("[LLOGIN SERVICE]: SetLevel failed, exception " + e.ToString()); | ||
270 | return response; | ||
271 | } | ||
272 | |||
273 | m_MinLoginLevel = level; | ||
274 | m_log.InfoFormat("[LLOGIN SERVICE]: Login level set to {0} by {1} {2}", level, firstName, lastName); | ||
275 | |||
276 | response["success"] = true; | ||
277 | return response; | ||
278 | } | ||
279 | |||
280 | public LoginResponse Login(string firstName, string lastName, string passwd, string startLocation, UUID scopeID, | ||
281 | string clientVersion, string channel, string mac, string id0, IPEndPoint clientIP, bool LibOMVclient) | ||
282 | { | ||
283 | bool success = false; | ||
284 | UUID session = UUID.Random(); | ||
285 | |||
286 | string processedMessage; | ||
287 | |||
288 | if (clientVersion.Contains("Radegast")) | ||
289 | LibOMVclient = false; | ||
290 | |||
291 | m_log.InfoFormat("[LLOGIN SERVICE]: Login request for {0} {1} at {2} using viewer {3}, channel {4}, IP {5}, Mac {6}, Id0 {7}, Possible LibOMVGridProxy: {8} ", | ||
292 | firstName, lastName, startLocation, clientVersion, channel, clientIP.Address.ToString(), mac, id0, LibOMVclient.ToString()); | ||
293 | |||
294 | try | ||
295 | { | ||
296 | // | ||
297 | // Check client | ||
298 | // | ||
299 | if (m_AllowedClients != string.Empty) | ||
300 | { | ||
301 | Regex arx = new Regex(m_AllowedClients); | ||
302 | Match am = arx.Match(clientVersion); | ||
303 | |||
304 | if (!am.Success) | ||
305 | { | ||
306 | m_log.InfoFormat( | ||
307 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: client {2} is not allowed", | ||
308 | firstName, lastName, clientVersion); | ||
309 | return LLFailedLoginResponse.LoginBlockedProblem; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | if (m_DeniedClients != string.Empty) | ||
314 | { | ||
315 | Regex drx = new Regex(m_DeniedClients); | ||
316 | Match dm = drx.Match(clientVersion); | ||
317 | |||
318 | if (dm.Success) | ||
319 | { | ||
320 | m_log.InfoFormat( | ||
321 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: client {2} is denied", | ||
322 | firstName, lastName, clientVersion); | ||
323 | return LLFailedLoginResponse.LoginBlockedProblem; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | // | ||
328 | // Get the account and check that it exists | ||
329 | // | ||
330 | UserAccount account = m_UserAccountService.GetUserAccount(scopeID, firstName, lastName); | ||
331 | if (account == null) | ||
332 | { | ||
333 | m_log.InfoFormat( | ||
334 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user not found", firstName, lastName); | ||
335 | return LLFailedLoginResponse.UserProblem; | ||
336 | } | ||
337 | |||
338 | if (account.UserLevel < m_MinLoginLevel) | ||
339 | { | ||
340 | m_log.InfoFormat( | ||
341 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user level is {2} but minimum login level is {3}", | ||
342 | firstName, lastName, account.UserLevel, m_MinLoginLevel); | ||
343 | return LLFailedLoginResponse.LoginBlockedProblem; | ||
344 | } | ||
345 | |||
346 | // If a scope id is requested, check that the account is in | ||
347 | // that scope, or unscoped. | ||
348 | // | ||
349 | if (scopeID != UUID.Zero) | ||
350 | { | ||
351 | if (account.ScopeID != scopeID && account.ScopeID != UUID.Zero) | ||
352 | { | ||
353 | m_log.InfoFormat( | ||
354 | "[LLOGIN SERVICE]: Login failed, reason: user {0} {1} not found", firstName, lastName); | ||
355 | return LLFailedLoginResponse.UserProblem; | ||
356 | } | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | scopeID = account.ScopeID; | ||
361 | } | ||
362 | |||
363 | // | ||
364 | // Authenticate this user | ||
365 | // | ||
366 | if (!passwd.StartsWith("$1$")) | ||
367 | passwd = "$1$" + Util.Md5Hash(passwd); | ||
368 | passwd = passwd.Remove(0, 3); //remove $1$ | ||
369 | UUID realID; | ||
370 | string token = m_AuthenticationService.Authenticate(account.PrincipalID, passwd, 30, out realID); | ||
371 | UUID secureSession = UUID.Zero; | ||
372 | if ((token == string.Empty) || (token != string.Empty && !UUID.TryParse(token, out secureSession))) | ||
373 | { | ||
374 | m_log.InfoFormat( | ||
375 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: authentication failed", | ||
376 | firstName, lastName); | ||
377 | return LLFailedLoginResponse.UserProblem; | ||
378 | } | ||
379 | |||
380 | if(account.PrincipalID == new UUID("6571e388-6218-4574-87db-f9379718315e")) | ||
381 | { | ||
382 | // really? | ||
383 | return LLFailedLoginResponse.UserProblem; | ||
384 | } | ||
385 | |||
386 | string PrincipalIDstr = account.PrincipalID.ToString(); | ||
387 | GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(PrincipalIDstr); | ||
388 | |||
389 | if(!m_allowDuplicatePresences) | ||
390 | { | ||
391 | if(guinfo != null && guinfo.Online && guinfo.LastRegionID != UUID.Zero) | ||
392 | { | ||
393 | // Also check Presence.UserID if RegionID == UUID.Zero, they are a ghost. | ||
394 | // Ghosting might be caused by failure to call PresenceService.LogoutAgent() on logout / crash / failed login. | ||
395 | // Might also need to double check if they are out hypergridding. | ||
396 | |||
397 | success = false; | ||
398 | if (m_PresenceService != null) | ||
399 | { | ||
400 | PresenceInfo pi = m_PresenceService.GetAgentByUser(account.PrincipalID); | ||
401 | if (null != pi) | ||
402 | { | ||
403 | Dictionary<string, object> pid = pi.ToKeyValuePairs(); | ||
404 | if (pid["RegionID"].ToString() == UUID.Zero.ToString()) | ||
405 | { | ||
406 | m_log.WarnFormat("[LLOGIN SERVICE]: Exorcising ghost avatar {0} {1}, session {2}, new session {3}.", firstName, lastName, pid["SessionID"], session); | ||
407 | success = m_PresenceService.LogoutAgent(new UUID(pid["SessionID"].ToString())); | ||
408 | if (success) | ||
409 | m_log.WarnFormat("[LLOGIN SERVICE]: Ghost avatar exorcised {0} {1}, session {2}, new session {3}.", firstName, lastName, pid["SessionID"], session); | ||
410 | else | ||
411 | m_log.ErrorFormat("[LLOGIN SERVICE]: Ghost avatar not exorcised {0} {1}, session {2}, new session {3}!", firstName, lastName, pid["SessionID"], session); | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | if ((!success) && SendAgentGodKillToRegion(scopeID, account.PrincipalID, guinfo)) | ||
417 | { | ||
418 | m_log.InfoFormat( | ||
419 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: already logged in", | ||
420 | firstName, lastName); | ||
421 | return LLFailedLoginResponse.AlreadyLoggedInProblem; | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | |||
426 | // | ||
427 | // Get the user's inventory | ||
428 | // | ||
429 | if (m_RequireInventory && m_InventoryService == null) | ||
430 | { | ||
431 | m_log.WarnFormat( | ||
432 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: inventory service not set up", | ||
433 | firstName, lastName); | ||
434 | return LLFailedLoginResponse.InventoryProblem; | ||
435 | } | ||
436 | |||
437 | if (m_HGInventoryService != null) | ||
438 | { | ||
439 | // Give the Suitcase service a chance to create the suitcase folder. | ||
440 | // (If we're not using the Suitcase inventory service then this won't do anything.) | ||
441 | m_HGInventoryService.GetRootFolder(account.PrincipalID); | ||
442 | } | ||
443 | |||
444 | List<InventoryFolderBase> inventorySkel = m_InventoryService.GetInventorySkeleton(account.PrincipalID); | ||
445 | if (m_RequireInventory && ((inventorySkel == null) || (inventorySkel != null && inventorySkel.Count == 0))) | ||
446 | { | ||
447 | m_log.InfoFormat( | ||
448 | "[LLOGIN SERVICE]: Login failed, for {0} {1}, reason: unable to retrieve user inventory", | ||
449 | firstName, lastName); | ||
450 | return LLFailedLoginResponse.InventoryProblem; | ||
451 | } | ||
452 | |||
453 | // Get active gestures | ||
454 | List<InventoryItemBase> gestures = m_InventoryService.GetActiveGestures(account.PrincipalID); | ||
455 | // m_log.DebugFormat("[LLOGIN SERVICE]: {0} active gestures", gestures.Count); | ||
456 | |||
457 | // | ||
458 | // Login the presence | ||
459 | // | ||
460 | if (m_PresenceService != null) | ||
461 | { | ||
462 | success = m_PresenceService.LoginAgent(PrincipalIDstr, session, secureSession); | ||
463 | |||
464 | if (!success) | ||
465 | { | ||
466 | m_log.InfoFormat( | ||
467 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: could not login presence", | ||
468 | firstName, lastName); | ||
469 | return LLFailedLoginResponse.GridProblem; | ||
470 | } | ||
471 | } | ||
472 | |||
473 | // | ||
474 | // Change Online status and get the home region | ||
475 | // | ||
476 | GridRegion home = null; | ||
477 | |||
478 | // We are only going to complain about no home if the user actually tries to login there, to avoid | ||
479 | // spamming the console. | ||
480 | if (guinfo != null) | ||
481 | { | ||
482 | if (guinfo.HomeRegionID == UUID.Zero && startLocation == "home") | ||
483 | { | ||
484 | m_log.WarnFormat( | ||
485 | "[LLOGIN SERVICE]: User {0} tried to login to a 'home' start location but they have none set", | ||
486 | account.Name); | ||
487 | } | ||
488 | else if (m_GridService != null) | ||
489 | { | ||
490 | home = m_GridService.GetRegionByUUID(scopeID, guinfo.HomeRegionID); | ||
491 | |||
492 | if (home == null && startLocation == "home") | ||
493 | { | ||
494 | m_log.WarnFormat( | ||
495 | "[LLOGIN SERVICE]: User {0} tried to login to a 'home' start location with ID {1} but this was not found.", | ||
496 | account.Name, guinfo.HomeRegionID); | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | else | ||
501 | { | ||
502 | // something went wrong, make something up, so that we don't have to test this anywhere else | ||
503 | m_log.DebugFormat("{0} Failed to fetch GridUserInfo. Creating empty GridUserInfo as home", LogHeader); | ||
504 | guinfo = new GridUserInfo(); | ||
505 | guinfo.LastPosition = guinfo.HomePosition = new Vector3(128, 128, 30); | ||
506 | } | ||
507 | |||
508 | // | ||
509 | // Find the destination region/grid | ||
510 | // | ||
511 | string where = string.Empty; | ||
512 | Vector3 position = Vector3.Zero; | ||
513 | Vector3 lookAt = Vector3.Zero; | ||
514 | GridRegion gatekeeper = null; | ||
515 | Constants.TeleportFlags flags; | ||
516 | GridRegion destination = FindDestination(account, scopeID, guinfo, session, startLocation, home, out gatekeeper, out where, out position, out lookAt, out flags); | ||
517 | if (destination == null) | ||
518 | { | ||
519 | m_PresenceService.LogoutAgent(session); | ||
520 | |||
521 | m_log.InfoFormat( | ||
522 | "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: destination not found", | ||
523 | firstName, lastName); | ||
524 | return LLFailedLoginResponse.GridProblem; | ||
525 | } | ||
526 | else | ||
527 | { | ||
528 | m_log.DebugFormat( | ||
529 | "[LLOGIN SERVICE]: Found destination {0}, endpoint {1} for {2} {3}", | ||
530 | destination.RegionName, destination.ExternalEndPoint, firstName, lastName); | ||
531 | } | ||
532 | |||
533 | if (account.UserLevel >= 200) | ||
534 | flags |= Constants.TeleportFlags.Godlike; | ||
535 | // | ||
536 | // Get the avatar | ||
537 | // | ||
538 | AvatarAppearance avatar = null; | ||
539 | if (m_AvatarService != null) | ||
540 | { | ||
541 | avatar = m_AvatarService.GetAppearance(account.PrincipalID); | ||
542 | } | ||
543 | |||
544 | // | ||
545 | // Instantiate/get the simulation interface and launch an agent at the destination | ||
546 | // | ||
547 | string reason = string.Empty; | ||
548 | GridRegion dest; | ||
549 | AgentCircuitData aCircuit = LaunchAgentAtGrid(gatekeeper, destination, account, avatar, session, secureSession, position, where, | ||
550 | clientVersion, channel, mac, id0, clientIP, flags, out where, out reason, out dest); | ||
551 | destination = dest; | ||
552 | if (aCircuit == null) | ||
553 | { | ||
554 | m_PresenceService.LogoutAgent(session); | ||
555 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed for {0} {1}, reason: {2}", firstName, lastName, reason); | ||
556 | return new LLFailedLoginResponse("key", reason, "false"); | ||
557 | |||
558 | } | ||
559 | |||
560 | // only now we can assume a login | ||
561 | guinfo = m_GridUserService.LoggedIn(PrincipalIDstr); | ||
562 | |||
563 | // Get Friends list | ||
564 | FriendInfo[] friendsList = new FriendInfo[0]; | ||
565 | if (m_FriendsService != null) | ||
566 | { | ||
567 | friendsList = m_FriendsService.GetFriends(account.PrincipalID); | ||
568 | // m_log.DebugFormat("[LLOGIN SERVICE]: Retrieved {0} friends", friendsList.Length); | ||
569 | } | ||
570 | |||
571 | // | ||
572 | // Finally, fill out the response and return it | ||
573 | // | ||
574 | if (m_MessageUrl != String.Empty) | ||
575 | { | ||
576 | using(WebClient client = new WebClient()) | ||
577 | processedMessage = client.DownloadString(m_MessageUrl); | ||
578 | } | ||
579 | else | ||
580 | { | ||
581 | processedMessage = m_WelcomeMessage; | ||
582 | } | ||
583 | processedMessage = processedMessage.Replace("\\n", "\n").Replace("<USERNAME>", firstName + " " + lastName); | ||
584 | |||
585 | LLLoginResponse response | ||
586 | = new LLLoginResponse( | ||
587 | account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, | ||
588 | where, startLocation, position, lookAt, gestures, processedMessage, home, clientIP, | ||
589 | m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone, | ||
590 | m_DestinationGuide, m_AvatarPicker, realID, m_ClassifiedFee,m_MaxAgentGroups); | ||
591 | |||
592 | m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName); | ||
593 | |||
594 | return response; | ||
595 | } | ||
596 | catch (Exception e) | ||
597 | { | ||
598 | m_log.WarnFormat("[LLOGIN SERVICE]: Exception processing login for {0} {1}: {2} {3}", firstName, lastName, e.ToString(), e.StackTrace); | ||
599 | if (m_PresenceService != null) | ||
600 | m_PresenceService.LogoutAgent(session); | ||
601 | return LLFailedLoginResponse.InternalError; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | protected GridRegion FindDestination( | ||
606 | UserAccount account, UUID scopeID, GridUserInfo pinfo, UUID sessionID, string startLocation, | ||
607 | GridRegion home, out GridRegion gatekeeper, | ||
608 | out string where, out Vector3 position, out Vector3 lookAt, out Constants.TeleportFlags flags) | ||
609 | { | ||
610 | flags = Constants.TeleportFlags.ViaLogin; | ||
611 | |||
612 | m_log.DebugFormat( | ||
613 | "[LLOGIN SERVICE]: Finding destination matching start location {0} for {1}", | ||
614 | startLocation, account.Name); | ||
615 | |||
616 | gatekeeper = null; | ||
617 | where = "home"; | ||
618 | position = new Vector3(128, 128, 0); | ||
619 | lookAt = new Vector3(0, 1, 0); | ||
620 | |||
621 | if (m_GridService == null) | ||
622 | return null; | ||
623 | |||
624 | if (startLocation.Equals("home")) | ||
625 | { | ||
626 | // logging into home region | ||
627 | if (pinfo == null) | ||
628 | return null; | ||
629 | |||
630 | GridRegion region = null; | ||
631 | |||
632 | bool tryDefaults = false; | ||
633 | |||
634 | if (home == null) | ||
635 | { | ||
636 | tryDefaults = true; | ||
637 | } | ||
638 | else | ||
639 | { | ||
640 | region = home; | ||
641 | |||
642 | position = pinfo.HomePosition; | ||
643 | lookAt = pinfo.HomeLookAt; | ||
644 | flags |= Constants.TeleportFlags.ViaHome; | ||
645 | } | ||
646 | |||
647 | if (tryDefaults) | ||
648 | { | ||
649 | List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID); | ||
650 | if (defaults != null && defaults.Count > 0) | ||
651 | { | ||
652 | flags |= Constants.TeleportFlags.ViaRegionID; | ||
653 | region = defaults[0]; | ||
654 | where = "safe"; | ||
655 | } | ||
656 | else | ||
657 | { | ||
658 | m_log.WarnFormat("[LLOGIN SERVICE]: User {0} {1} does not have a valid home and this grid does not have default locations. Attempting to find random region", | ||
659 | account.FirstName, account.LastName); | ||
660 | region = FindAlternativeRegion(scopeID); | ||
661 | if (region != null) | ||
662 | { | ||
663 | flags |= Constants.TeleportFlags.ViaRegionID; | ||
664 | where = "safe"; | ||
665 | } | ||
666 | } | ||
667 | } | ||
668 | |||
669 | return region; | ||
670 | } | ||
671 | else if (startLocation.Equals("last")) | ||
672 | { | ||
673 | // logging into last visited region | ||
674 | where = "last"; | ||
675 | |||
676 | if (pinfo == null) | ||
677 | return null; | ||
678 | |||
679 | GridRegion region = null; | ||
680 | |||
681 | if (pinfo.LastRegionID.Equals(UUID.Zero) || (region = m_GridService.GetRegionByUUID(scopeID, pinfo.LastRegionID)) == null) | ||
682 | { | ||
683 | List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID); | ||
684 | if (defaults != null && defaults.Count > 0) | ||
685 | { | ||
686 | flags |= Constants.TeleportFlags.ViaRegionID; | ||
687 | region = defaults[0]; | ||
688 | where = "safe"; | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | m_log.Info("[LLOGIN SERVICE]: Last Region Not Found Attempting to find random region"); | ||
693 | region = FindAlternativeRegion(scopeID); | ||
694 | if (region != null) | ||
695 | { | ||
696 | flags |= Constants.TeleportFlags.ViaRegionID; | ||
697 | where = "safe"; | ||
698 | } | ||
699 | } | ||
700 | |||
701 | } | ||
702 | else | ||
703 | { | ||
704 | position = pinfo.LastPosition; | ||
705 | lookAt = pinfo.LastLookAt; | ||
706 | } | ||
707 | |||
708 | return region; | ||
709 | } | ||
710 | else | ||
711 | { | ||
712 | flags |= Constants.TeleportFlags.ViaRegionID; | ||
713 | |||
714 | // free uri form | ||
715 | // e.g. New Moon&135&46 New Moon@osgrid.org:8002&153&34 | ||
716 | where = "url"; | ||
717 | GridRegion region = null; | ||
718 | Regex reURI = new Regex(@"^uri:(?<region>[^&]+)&(?<x>\d+[.]?\d*)&(?<y>\d+[.]?\d*)&(?<z>\d+[.]?\d*)$"); | ||
719 | Match uriMatch = reURI.Match(startLocation); | ||
720 | if (uriMatch == null) | ||
721 | { | ||
722 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, but can't process it", startLocation); | ||
723 | return null; | ||
724 | } | ||
725 | else | ||
726 | { | ||
727 | position = new Vector3(float.Parse(uriMatch.Groups["x"].Value, Culture.NumberFormatInfo), | ||
728 | float.Parse(uriMatch.Groups["y"].Value, Culture.NumberFormatInfo), | ||
729 | float.Parse(uriMatch.Groups["z"].Value, Culture.NumberFormatInfo)); | ||
730 | if (0 == position.Z) | ||
731 | flags |= Constants.TeleportFlags.ViaMap; | ||
732 | |||
733 | string regionName = uriMatch.Groups["region"].ToString(); | ||
734 | if (regionName != null) | ||
735 | { | ||
736 | if (!regionName.Contains("@")) | ||
737 | { | ||
738 | List<GridRegion> regions = m_GridService.GetRegionsByName(scopeID, regionName, 1); | ||
739 | if ((regions == null) || (regions != null && regions.Count == 0)) | ||
740 | { | ||
741 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, can't locate region {1}. Trying defaults.", startLocation, regionName); | ||
742 | regions = m_GridService.GetDefaultRegions(scopeID); | ||
743 | if (regions != null && regions.Count > 0) | ||
744 | { | ||
745 | where = "safe"; | ||
746 | return regions[0]; | ||
747 | } | ||
748 | else | ||
749 | { | ||
750 | m_log.Info("[LLOGIN SERVICE]: Last Region Not Found Attempting to find random region"); | ||
751 | region = FindAlternativeRegion(scopeID); | ||
752 | if (region != null) | ||
753 | { | ||
754 | where = "safe"; | ||
755 | return region; | ||
756 | } | ||
757 | else | ||
758 | { | ||
759 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, Grid does not provide default regions and no alternative found.", startLocation); | ||
760 | return null; | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | return regions[0]; | ||
765 | } | ||
766 | else | ||
767 | { | ||
768 | if (m_UserAgentService == null) | ||
769 | { | ||
770 | m_log.WarnFormat("[LLLOGIN SERVICE]: This llogin service is not running a user agent service, as such it can't lauch agents at foreign grids"); | ||
771 | return null; | ||
772 | } | ||
773 | string[] parts = regionName.Split(new char[] { '@' }); | ||
774 | if (parts.Length < 2) | ||
775 | { | ||
776 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, can't locate region {1}", startLocation, regionName); | ||
777 | return null; | ||
778 | } | ||
779 | // Valid specification of a remote grid | ||
780 | |||
781 | regionName = parts[0]; | ||
782 | string domainLocator = parts[1]; | ||
783 | parts = domainLocator.Split(new char[] {':'}); | ||
784 | string domainName = parts[0]; | ||
785 | uint port = 0; | ||
786 | if (parts.Length > 1) | ||
787 | UInt32.TryParse(parts[1], out port); | ||
788 | |||
789 | region = FindForeignRegion(domainName, port, regionName, account, out gatekeeper); | ||
790 | return region; | ||
791 | } | ||
792 | } | ||
793 | else | ||
794 | { | ||
795 | List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID); | ||
796 | if (defaults != null && defaults.Count > 0) | ||
797 | { | ||
798 | where = "safe"; | ||
799 | return defaults[0]; | ||
800 | } | ||
801 | else | ||
802 | return null; | ||
803 | } | ||
804 | } | ||
805 | //response.LookAt = "[r0,r1,r0]"; | ||
806 | //// can be: last, home, safe, url | ||
807 | //response.StartLocation = "url"; | ||
808 | |||
809 | } | ||
810 | |||
811 | } | ||
812 | |||
813 | private GridRegion FindAlternativeRegion(UUID scopeID) | ||
814 | { | ||
815 | List<GridRegion> hyperlinks = null; | ||
816 | List<GridRegion> regions = m_GridService.GetFallbackRegions(scopeID, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000)); | ||
817 | if (regions != null && regions.Count > 0) | ||
818 | { | ||
819 | hyperlinks = m_GridService.GetHyperlinks(scopeID); | ||
820 | IEnumerable<GridRegion> availableRegions = regions.Except(hyperlinks); | ||
821 | if (availableRegions.Count() > 0) | ||
822 | return availableRegions.ElementAt(0); | ||
823 | } | ||
824 | // No fallbacks, try to find an arbitrary region that is not a hyperlink | ||
825 | // maxNumber is fixed for now; maybe use some search pattern with increasing maxSize here? | ||
826 | regions = m_GridService.GetRegionsByName(scopeID, "", 10); | ||
827 | if (regions != null && regions.Count > 0) | ||
828 | { | ||
829 | if (hyperlinks == null) | ||
830 | hyperlinks = m_GridService.GetHyperlinks(scopeID); | ||
831 | IEnumerable<GridRegion> availableRegions = regions.Except(hyperlinks); | ||
832 | if (availableRegions.Count() > 0) | ||
833 | return availableRegions.ElementAt(0); | ||
834 | } | ||
835 | return null; | ||
836 | } | ||
837 | |||
838 | private GridRegion FindForeignRegion(string domainName, uint port, string regionName, UserAccount account, out GridRegion gatekeeper) | ||
839 | { | ||
840 | m_log.Debug("[LLLOGIN SERVICE]: attempting to findforeignregion " + domainName + ":" + port.ToString() + ":" + regionName); | ||
841 | gatekeeper = new GridRegion(); | ||
842 | gatekeeper.ExternalHostName = domainName; | ||
843 | gatekeeper.HttpPort = port; | ||
844 | gatekeeper.RegionName = regionName; | ||
845 | gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); | ||
846 | |||
847 | UUID regionID; | ||
848 | ulong handle; | ||
849 | string imageURL = string.Empty, reason = string.Empty; | ||
850 | string message; | ||
851 | int sizeX = (int)Constants.RegionSize; | ||
852 | int sizeY = (int)Constants.RegionSize; | ||
853 | |||
854 | if (m_GatekeeperConnector.LinkRegion(gatekeeper, out regionID, out handle, out domainName, out imageURL, out reason, out sizeX, out sizeY)) | ||
855 | { | ||
856 | string homeURI = null; | ||
857 | if (account.ServiceURLs != null && account.ServiceURLs.ContainsKey("HomeURI")) | ||
858 | homeURI = (string)account.ServiceURLs["HomeURI"]; | ||
859 | |||
860 | GridRegion destination = m_GatekeeperConnector.GetHyperlinkRegion(gatekeeper, regionID, account.PrincipalID, homeURI, out message); | ||
861 | return destination; | ||
862 | } | ||
863 | |||
864 | return null; | ||
865 | } | ||
866 | |||
867 | private string hostName = string.Empty; | ||
868 | private int port = 0; | ||
869 | |||
870 | private void SetHostAndPort(string url) | ||
871 | { | ||
872 | try | ||
873 | { | ||
874 | Uri uri = new Uri(url); | ||
875 | hostName = uri.Host; | ||
876 | port = uri.Port; | ||
877 | } | ||
878 | catch | ||
879 | { | ||
880 | m_log.WarnFormat("[LLLogin SERVICE]: Unable to parse GatekeeperURL {0}", url); | ||
881 | } | ||
882 | } | ||
883 | |||
884 | protected AgentCircuitData LaunchAgentAtGrid(GridRegion gatekeeper, GridRegion destination, UserAccount account, AvatarAppearance avatar, | ||
885 | UUID session, UUID secureSession, Vector3 position, string currentWhere, string viewer, string channel, string mac, string id0, | ||
886 | IPEndPoint clientIP, Constants.TeleportFlags flags, out string where, out string reason, out GridRegion dest) | ||
887 | { | ||
888 | where = currentWhere; | ||
889 | ISimulationService simConnector = null; | ||
890 | reason = string.Empty; | ||
891 | uint circuitCode = 0; | ||
892 | AgentCircuitData aCircuit = null; | ||
893 | dest = null; | ||
894 | |||
895 | bool success = false; | ||
896 | |||
897 | if (m_UserAgentService == null) | ||
898 | { | ||
899 | // HG standalones have both a localSimulatonDll and a remoteSimulationDll | ||
900 | // non-HG standalones have just a localSimulationDll | ||
901 | // independent login servers have just a remoteSimulationDll | ||
902 | if (m_LocalSimulationService != null) | ||
903 | simConnector = m_LocalSimulationService; | ||
904 | else if (m_RemoteSimulationService != null) | ||
905 | simConnector = m_RemoteSimulationService; | ||
906 | |||
907 | if(simConnector == null) | ||
908 | return null; | ||
909 | |||
910 | circuitCode = (uint)Util.RandomClass.Next(); ; | ||
911 | aCircuit = MakeAgent(destination, account, avatar, session, secureSession, circuitCode, position, | ||
912 | clientIP.Address.ToString(), viewer, channel, mac, id0); | ||
913 | |||
914 | success = LaunchAgentDirectly(simConnector, destination, aCircuit, flags, out reason); | ||
915 | if (!success && m_GridService != null) | ||
916 | { | ||
917 | // Try the fallback regions | ||
918 | List<GridRegion> fallbacks = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY); | ||
919 | if (fallbacks != null) | ||
920 | { | ||
921 | foreach (GridRegion r in fallbacks) | ||
922 | { | ||
923 | success = LaunchAgentDirectly(simConnector, r, aCircuit, flags | Constants.TeleportFlags.ViaRegionID | Constants.TeleportFlags.ViaMap, out reason); | ||
924 | if (success) | ||
925 | { | ||
926 | where = "safe"; | ||
927 | destination = r; | ||
928 | break; | ||
929 | } | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | } | ||
934 | |||
935 | else | ||
936 | { | ||
937 | if (gatekeeper == null) // login to local grid | ||
938 | { | ||
939 | if (hostName == string.Empty) | ||
940 | SetHostAndPort(m_GatekeeperURL); | ||
941 | |||
942 | gatekeeper = new GridRegion(destination); | ||
943 | gatekeeper.ExternalHostName = hostName; | ||
944 | gatekeeper.HttpPort = (uint)port; | ||
945 | gatekeeper.ServerURI = m_GatekeeperURL; | ||
946 | } | ||
947 | circuitCode = (uint)Util.RandomClass.Next(); ; | ||
948 | aCircuit = MakeAgent(destination, account, avatar, session, secureSession, circuitCode, position, | ||
949 | clientIP.Address.ToString(), viewer, channel, mac, id0); | ||
950 | |||
951 | aCircuit.teleportFlags |= (uint)flags; | ||
952 | success = LaunchAgentIndirectly(gatekeeper, destination, aCircuit, clientIP, out reason); | ||
953 | if (!success && m_GridService != null) | ||
954 | { | ||
955 | // Try the fallback regions | ||
956 | List<GridRegion> fallbacks = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY); | ||
957 | if (fallbacks != null) | ||
958 | { | ||
959 | foreach (GridRegion r in fallbacks) | ||
960 | { | ||
961 | success = LaunchAgentIndirectly(gatekeeper, r, aCircuit, clientIP, out reason); | ||
962 | if (success) | ||
963 | { | ||
964 | where = "safe"; | ||
965 | destination = r; | ||
966 | break; | ||
967 | } | ||
968 | } | ||
969 | } | ||
970 | } | ||
971 | } | ||
972 | dest = destination; | ||
973 | if (success) | ||
974 | return aCircuit; | ||
975 | else | ||
976 | return null; | ||
977 | } | ||
978 | |||
979 | private AgentCircuitData MakeAgent(GridRegion region, UserAccount account, | ||
980 | AvatarAppearance avatar, UUID session, UUID secureSession, uint circuit, Vector3 position, | ||
981 | string ipaddress, string viewer, string channel, string mac, string id0) | ||
982 | { | ||
983 | AgentCircuitData aCircuit = new AgentCircuitData(); | ||
984 | |||
985 | aCircuit.AgentID = account.PrincipalID; | ||
986 | if (avatar != null) | ||
987 | aCircuit.Appearance = new AvatarAppearance(avatar); | ||
988 | else | ||
989 | aCircuit.Appearance = new AvatarAppearance(); | ||
990 | |||
991 | //aCircuit.BaseFolder = irrelevant | ||
992 | aCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | ||
993 | aCircuit.child = false; // the first login agent is root | ||
994 | aCircuit.ChildrenCapSeeds = new Dictionary<ulong, string>(); | ||
995 | aCircuit.circuitcode = circuit; | ||
996 | aCircuit.firstname = account.FirstName; | ||
997 | //aCircuit.InventoryFolder = irrelevant | ||
998 | aCircuit.lastname = account.LastName; | ||
999 | aCircuit.SecureSessionID = secureSession; | ||
1000 | aCircuit.SessionID = session; | ||
1001 | aCircuit.startpos = position; | ||
1002 | aCircuit.IPAddress = ipaddress; | ||
1003 | aCircuit.Viewer = viewer; | ||
1004 | aCircuit.Channel = channel; | ||
1005 | aCircuit.Mac = mac; | ||
1006 | aCircuit.Id0 = id0; | ||
1007 | SetServiceURLs(aCircuit, account); | ||
1008 | |||
1009 | return aCircuit; | ||
1010 | } | ||
1011 | |||
1012 | private void SetServiceURLs(AgentCircuitData aCircuit, UserAccount account) | ||
1013 | { | ||
1014 | aCircuit.ServiceURLs = new Dictionary<string, object>(); | ||
1015 | if (account.ServiceURLs == null) | ||
1016 | return; | ||
1017 | |||
1018 | // Old style: get the service keys from the DB | ||
1019 | foreach (KeyValuePair<string, object> kvp in account.ServiceURLs) | ||
1020 | { | ||
1021 | if (kvp.Value != null) | ||
1022 | { | ||
1023 | aCircuit.ServiceURLs[kvp.Key] = kvp.Value; | ||
1024 | |||
1025 | if (!aCircuit.ServiceURLs[kvp.Key].ToString().EndsWith("/")) | ||
1026 | aCircuit.ServiceURLs[kvp.Key] = aCircuit.ServiceURLs[kvp.Key] + "/"; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | // New style: service keys start with SRV_; override the previous | ||
1031 | string[] keys = m_LoginServerConfig.GetKeys(); | ||
1032 | |||
1033 | if (keys.Length > 0) | ||
1034 | { | ||
1035 | bool newUrls = false; | ||
1036 | IEnumerable<string> serviceKeys = keys.Where(value => value.StartsWith("SRV_")); | ||
1037 | foreach (string serviceKey in serviceKeys) | ||
1038 | { | ||
1039 | string keyName = serviceKey.Replace("SRV_", ""); | ||
1040 | string keyValue = m_LoginServerConfig.GetString(serviceKey, string.Empty); | ||
1041 | if (!keyValue.EndsWith("/")) | ||
1042 | keyValue = keyValue + "/"; | ||
1043 | |||
1044 | if (!account.ServiceURLs.ContainsKey(keyName) || (account.ServiceURLs.ContainsKey(keyName) && (string)account.ServiceURLs[keyName] != keyValue)) | ||
1045 | { | ||
1046 | account.ServiceURLs[keyName] = keyValue; | ||
1047 | newUrls = true; | ||
1048 | } | ||
1049 | aCircuit.ServiceURLs[keyName] = keyValue; | ||
1050 | |||
1051 | m_log.DebugFormat("[LLLOGIN SERVICE]: found new key {0} {1}", keyName, aCircuit.ServiceURLs[keyName]); | ||
1052 | } | ||
1053 | |||
1054 | if (!account.ServiceURLs.ContainsKey("GatekeeperURI") && !string.IsNullOrEmpty(m_GatekeeperURL)) | ||
1055 | { | ||
1056 | m_log.DebugFormat("[LLLOGIN SERVICE]: adding gatekeeper uri {0}", m_GatekeeperURL); | ||
1057 | account.ServiceURLs["GatekeeperURI"] = m_GatekeeperURL; | ||
1058 | newUrls = true; | ||
1059 | } | ||
1060 | |||
1061 | // The grid operator decided to override the defaults in the | ||
1062 | // [LoginService] configuration. Let's store the correct ones. | ||
1063 | if (newUrls) | ||
1064 | m_UserAccountService.StoreUserAccount(account); | ||
1065 | } | ||
1066 | |||
1067 | } | ||
1068 | |||
1069 | private bool LaunchAgentDirectly(ISimulationService simConnector, GridRegion region, AgentCircuitData aCircuit, Constants.TeleportFlags flags, out string reason) | ||
1070 | { | ||
1071 | EntityTransferContext ctx = new EntityTransferContext(); | ||
1072 | |||
1073 | if (!simConnector.QueryAccess( | ||
1074 | region, aCircuit.AgentID, null, true, aCircuit.startpos, new List<UUID>(), ctx, out reason)) | ||
1075 | return false; | ||
1076 | |||
1077 | return simConnector.CreateAgent(null, region, aCircuit, (uint)flags, ctx, out reason); | ||
1078 | } | ||
1079 | |||
1080 | private bool LaunchAgentIndirectly(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, IPEndPoint clientIP, out string reason) | ||
1081 | { | ||
1082 | m_log.Debug("[LLOGIN SERVICE]: Launching agent at " + destination.RegionName); | ||
1083 | |||
1084 | if (m_UserAgentService.LoginAgentToGrid(null, aCircuit, gatekeeper, destination, true, out reason)) | ||
1085 | return true; | ||
1086 | return false; | ||
1087 | } | ||
1088 | |||
1089 | #region Console Commands | ||
1090 | private void RegisterCommands() | ||
1091 | { | ||
1092 | //MainConsole.Instance.Commands.AddCommand | ||
1093 | MainConsole.Instance.Commands.AddCommand("Users", false, "login level", | ||
1094 | "login level <level>", | ||
1095 | "Set the minimum user level to log in", HandleLoginCommand); | ||
1096 | |||
1097 | MainConsole.Instance.Commands.AddCommand("Users", false, "login reset", | ||
1098 | "login reset", | ||
1099 | "Reset the login level to allow all users", | ||
1100 | HandleLoginCommand); | ||
1101 | |||
1102 | MainConsole.Instance.Commands.AddCommand("Users", false, "login text", | ||
1103 | "login text <text>", | ||
1104 | "Set the text users will see on login", HandleLoginCommand); | ||
1105 | |||
1106 | } | ||
1107 | |||
1108 | private void HandleLoginCommand(string module, string[] cmd) | ||
1109 | { | ||
1110 | string subcommand = cmd[1]; | ||
1111 | |||
1112 | switch (subcommand) | ||
1113 | { | ||
1114 | case "level": | ||
1115 | // Set the minimum level to allow login | ||
1116 | // Useful to allow grid update without worrying about users. | ||
1117 | // or fixing critical issues | ||
1118 | // | ||
1119 | if (cmd.Length > 2) | ||
1120 | { | ||
1121 | if (Int32.TryParse(cmd[2], out m_MinLoginLevel)) | ||
1122 | MainConsole.Instance.OutputFormat("Set minimum login level to {0}", m_MinLoginLevel); | ||
1123 | else | ||
1124 | MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid login level", cmd[2]); | ||
1125 | } | ||
1126 | break; | ||
1127 | |||
1128 | case "reset": | ||
1129 | m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0); | ||
1130 | MainConsole.Instance.OutputFormat("Reset min login level to {0}", m_MinLoginLevel); | ||
1131 | break; | ||
1132 | |||
1133 | case "text": | ||
1134 | if (cmd.Length > 2) | ||
1135 | { | ||
1136 | m_WelcomeMessage = cmd[2]; | ||
1137 | MainConsole.Instance.OutputFormat("Login welcome message set to '{0}'", m_WelcomeMessage); | ||
1138 | } | ||
1139 | break; | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | private bool SendAgentGodKillToRegion(UUID scopeID, UUID agentID , GridUserInfo guinfo) | ||
1144 | { | ||
1145 | UUID regionID = guinfo.LastRegionID; | ||
1146 | GridRegion regInfo = m_GridService.GetRegionByUUID(scopeID, regionID); | ||
1147 | if(regInfo == null) | ||
1148 | return false; | ||
1149 | |||
1150 | string regURL = regInfo.ServerURI; | ||
1151 | if(String.IsNullOrEmpty(regURL)) | ||
1152 | return false; | ||
1153 | |||
1154 | UUID guuid = new UUID("6571e388-6218-4574-87db-f9379718315e"); | ||
1155 | |||
1156 | GridInstantMessage msg = new GridInstantMessage(); | ||
1157 | msg.imSessionID = UUID.Zero.Guid; | ||
1158 | msg.fromAgentID = guuid.Guid; | ||
1159 | msg.toAgentID = agentID.Guid; | ||
1160 | msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); | ||
1161 | msg.fromAgentName = "GRID"; | ||
1162 | msg.message = string.Format("New login detected"); | ||
1163 | msg.dialog = 250; // God kick | ||
1164 | msg.fromGroup = false; | ||
1165 | msg.offline = (byte)0; | ||
1166 | msg.ParentEstateID = 0; | ||
1167 | msg.Position = Vector3.Zero; | ||
1168 | msg.RegionID = scopeID.Guid; | ||
1169 | msg.binaryBucket = new byte[1] {0}; | ||
1170 | InstantMessageServiceConnector.SendInstantMessage(regURL,msg); | ||
1171 | |||
1172 | m_GridUserService.LoggedOut(agentID.ToString(), | ||
1173 | UUID.Zero, guinfo.LastRegionID, guinfo.LastPosition, guinfo.LastLookAt); | ||
1174 | |||
1175 | return true; | ||
1176 | } | ||
1177 | } | ||
1178 | |||
1179 | #endregion | ||
1180 | } | ||