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