aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/LLLoginService/LLLoginService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/LLLoginService/LLLoginService.cs')
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs1180
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Linq;
32using System.Net;
33using System.Reflection;
34using System.Text.RegularExpressions;
35
36using log4net;
37using Nini.Config;
38using OpenMetaverse;
39
40using OpenSim.Framework;
41using OpenSim.Framework.Console;
42using OpenSim.Server.Base;
43using OpenSim.Services.Connectors.InstantMessage;
44using OpenSim.Services.Interfaces;
45using GridRegion = OpenSim.Services.Interfaces.GridRegion;
46using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
47using OpenSim.Services.Connectors.Hypergrid;
48
49namespace 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}