opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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.Generic;
30 using System.Net;
31 using System.Reflection;
32 using System.Text.RegularExpressions;
33  
34 using OpenSim.Framework;
35 using OpenSim.Services.Interfaces;
36 using GridRegion = OpenSim.Services.Interfaces.GridRegion;
37 using OpenSim.Server.Base;
38 using OpenSim.Services.Connectors.Hypergrid;
39  
40 using OpenMetaverse;
41  
42 using Nini.Config;
43 using log4net;
44  
45 namespace OpenSim.Services.HypergridService
46 {
47 public class GatekeeperService : IGatekeeperService
48 {
49 private static readonly ILog m_log =
50 LogManager.GetLogger(
51 MethodBase.GetCurrentMethod().DeclaringType);
52  
53 private static bool m_Initialized = false;
54  
55 private static IGridService m_GridService;
56 private static IPresenceService m_PresenceService;
57 private static IUserAccountService m_UserAccountService;
58 private static IUserAgentService m_UserAgentService;
59 private static ISimulationService m_SimulationService;
60 private static IGridUserService m_GridUserService;
61 private static IBansService m_BansService;
62  
63 private static string m_AllowedClients = string.Empty;
64 private static string m_DeniedClients = string.Empty;
65 private static bool m_ForeignAgentsAllowed = true;
66 private static List<string> m_ForeignsAllowedExceptions = new List<string>();
67 private static List<string> m_ForeignsDisallowedExceptions = new List<string>();
68  
69 private static UUID m_ScopeID;
70 private static bool m_AllowTeleportsToAnyRegion;
71 private static string m_ExternalName;
72 private static Uri m_Uri;
73 private static GridRegion m_DefaultGatewayRegion;
74  
75 public GatekeeperService(IConfigSource config, ISimulationService simService)
76 {
77 if (!m_Initialized)
78 {
79 m_Initialized = true;
80  
81 IConfig serverConfig = config.Configs["GatekeeperService"];
82 if (serverConfig == null)
83 throw new Exception(String.Format("No section GatekeeperService in config file"));
84  
85 string accountService = serverConfig.GetString("UserAccountService", String.Empty);
86 string homeUsersService = serverConfig.GetString("UserAgentService", string.Empty);
87 string gridService = serverConfig.GetString("GridService", String.Empty);
88 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
89 string simulationService = serverConfig.GetString("SimulationService", String.Empty);
90 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
91 string bansService = serverConfig.GetString("BansService", String.Empty);
92  
93 // These are mandatory, the others aren't
94 if (gridService == string.Empty || presenceService == string.Empty)
95 throw new Exception("Incomplete specifications, Gatekeeper Service cannot function.");
96  
97 string scope = serverConfig.GetString("ScopeID", UUID.Zero.ToString());
98 UUID.TryParse(scope, out m_ScopeID);
99 //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!");
100 m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true);
101 m_ExternalName = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
102 new string[] { "Startup", "Hypergrid", "GatekeeperService" }, String.Empty);
103 m_ExternalName = serverConfig.GetString("ExternalName", m_ExternalName);
104 if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/"))
105 m_ExternalName = m_ExternalName + "/";
106  
107 try
108 {
109 m_Uri = new Uri(m_ExternalName);
110 }
111 catch
112 {
113 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed gatekeeper address {0}", m_ExternalName);
114 }
115  
116 Object[] args = new Object[] { config };
117 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
118 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
119  
120 if (accountService != string.Empty)
121 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
122 if (homeUsersService != string.Empty)
123 m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args);
124 if (gridUserService != string.Empty)
125 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
126 if (bansService != string.Empty)
127 m_BansService = ServerUtils.LoadPlugin<IBansService>(bansService, args);
128  
129 if (simService != null)
130 m_SimulationService = simService;
131 else if (simulationService != string.Empty)
132 m_SimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args);
133  
134 m_AllowedClients = serverConfig.GetString("AllowedClients", string.Empty);
135 m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty);
136 m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true);
137  
138 LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_ForeignsAllowedExceptions);
139 LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_ForeignsDisallowedExceptions);
140  
141 if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
142 throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
143  
144 m_log.Debug("[GATEKEEPER SERVICE]: Starting...");
145 }
146 }
147  
148 public GatekeeperService(IConfigSource config)
149 : this(config, null)
150 {
151 }
152  
153 protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, List<string> exceptions)
154 {
155 string value = config.GetString(variable, string.Empty);
156 string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
157  
158 foreach (string s in parts)
159 exceptions.Add(s.Trim());
160 }
161  
162 public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
163 {
164 regionID = UUID.Zero;
165 regionHandle = 0;
166 externalName = m_ExternalName + ((regionName != string.Empty) ? " " + regionName : "");
167 imageURL = string.Empty;
168 reason = string.Empty;
169 GridRegion region = null;
170  
171 m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName);
172 if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty)
173 {
174 List<GridRegion> defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID);
175 if (defs != null && defs.Count > 0)
176 {
177 region = defs[0];
178 m_DefaultGatewayRegion = region;
179 }
180 else
181 {
182 reason = "Grid setup problem. Try specifying a particular region here.";
183 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to send information. Please specify a default region for this grid!");
184 return false;
185 }
186 }
187 else
188 {
189 region = m_GridService.GetRegionByName(m_ScopeID, regionName);
190 if (region == null)
191 {
192 reason = "Region not found";
193 return false;
194 }
195 }
196  
197 regionID = region.RegionID;
198 regionHandle = region.RegionHandle;
199  
200 string regionimage = "regionImage" + regionID.ToString();
201 regionimage = regionimage.Replace("-", "");
202 imageURL = region.ServerURI + "index.php?method=" + regionimage;
203  
204 return true;
205 }
206  
207 public GridRegion GetHyperlinkRegion(UUID regionID)
208 {
209 m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to get hyperlink region {0}", regionID);
210  
211 if (!m_AllowTeleportsToAnyRegion)
212 // Don't even check the given regionID
213 return m_DefaultGatewayRegion;
214  
215 GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID);
216 return region;
217 }
218  
219 #region Login Agent
220 public bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason)
221 {
222 reason = string.Empty;
223  
224 string authURL = string.Empty;
225 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
226 authURL = aCircuit.ServiceURLs["HomeURI"].ToString();
227 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9} Teleport Flags {10}",
228 aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName,
229 aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, aCircuit.teleportFlags.ToString());
230  
231 //
232 // Check client
233 //
234 if (m_AllowedClients != string.Empty)
235 {
236 Regex arx = new Regex(m_AllowedClients);
237 Match am = arx.Match(aCircuit.Viewer);
238  
239 if (!am.Success)
240 {
241 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", aCircuit.Viewer);
242 return false;
243 }
244 }
245  
246 if (m_DeniedClients != string.Empty)
247 {
248 Regex drx = new Regex(m_DeniedClients);
249 Match dm = drx.Match(aCircuit.Viewer);
250  
251 if (dm.Success)
252 {
253 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", aCircuit.Viewer);
254 return false;
255 }
256 }
257  
258 //
259 // Authenticate the user
260 //
261 if (!Authenticate(aCircuit))
262 {
263 reason = "Unable to verify identity";
264 m_log.InfoFormat("[GATEKEEPER SERVICE]: Unable to verify identity of agent {0} {1}. Refusing service.", aCircuit.firstname, aCircuit.lastname);
265 return false;
266 }
267 m_log.DebugFormat("[GATEKEEPER SERVICE]: Identity verified for {0} {1} @ {2}", aCircuit.firstname, aCircuit.lastname, authURL);
268  
269 //
270 // Check for impersonations
271 //
272 UserAccount account = null;
273 if (m_UserAccountService != null)
274 {
275 // Check to see if we have a local user with that UUID
276 account = m_UserAccountService.GetUserAccount(m_ScopeID, aCircuit.AgentID);
277 if (account != null)
278 {
279 // Make sure this is the user coming home, and not a foreign user with same UUID as a local user
280 if (m_UserAgentService != null)
281 {
282 if (!m_UserAgentService.IsAgentComingHome(aCircuit.SessionID, m_ExternalName))
283 {
284 // Can't do, sorry
285 reason = "Unauthorized";
286 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agent {0} {1} has same ID as local user. Refusing service.",
287 aCircuit.firstname, aCircuit.lastname);
288 return false;
289  
290 }
291 }
292 }
293 }
294  
295 //
296 // Foreign agents allowed? Exceptions?
297 //
298 if (account == null)
299 {
300 bool allowed = m_ForeignAgentsAllowed;
301  
302 if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
303 allowed = false;
304  
305 if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
306 allowed = true;
307  
308 if (!allowed)
309 {
310 reason = "Destination does not allow visitors from your world";
311 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1} @ {2}. Refusing service.",
312 aCircuit.firstname, aCircuit.lastname, aCircuit.ServiceURLs["HomeURI"]);
313 return false;
314 }
315 }
316  
317 //
318 // Is the user banned?
319 // This uses a Ban service that's more powerful than the configs
320 //
321 string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit));
322 if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL))
323 {
324 reason = "You are banned from this world";
325 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui);
326 return false;
327 }
328  
329 m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name);
330  
331 bool isFirstLogin = false;
332 //
333 // Login the presence, if it's not there yet (by the login service)
334 //
335 PresenceInfo presence = m_PresenceService.GetAgent(aCircuit.SessionID);
336 if (presence != null) // it has been placed there by the login service
337 isFirstLogin = true;
338  
339 else
340 {
341 if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
342 {
343 reason = "Unable to login presence";
344 m_log.InfoFormat("[GATEKEEPER SERVICE]: Presence login failed for foreign agent {0} {1}. Refusing service.",
345 aCircuit.firstname, aCircuit.lastname);
346 return false;
347 }
348  
349 m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name);
350  
351 // Also login foreigners with GridUser service
352 if (m_GridUserService != null && account == null)
353 {
354 string userId = aCircuit.AgentID.ToString();
355 string first = aCircuit.firstname, last = aCircuit.lastname;
356 if (last.StartsWith("@"))
357 {
358 string[] parts = aCircuit.firstname.Split('.');
359 if (parts.Length >= 2)
360 {
361 first = parts[0];
362 last = parts[1];
363 }
364 }
365  
366 userId += ";" + aCircuit.ServiceURLs["HomeURI"] + ";" + first + " " + last;
367 m_GridUserService.LoggedIn(userId);
368 }
369 }
370  
371 //
372 // Get the region
373 //
374 destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID);
375 if (destination == null)
376 {
377 reason = "Destination region not found";
378 return false;
379 }
380  
381 m_log.DebugFormat(
382 "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name);
383  
384 //
385 // Adjust the visible name
386 //
387 if (account != null)
388 {
389 aCircuit.firstname = account.FirstName;
390 aCircuit.lastname = account.LastName;
391 }
392 if (account == null)
393 {
394 if (!aCircuit.lastname.StartsWith("@"))
395 aCircuit.firstname = aCircuit.firstname + "." + aCircuit.lastname;
396 try
397 {
398 Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString());
399 aCircuit.lastname = "@" + uri.Host; // + ":" + uri.Port;
400 }
401 catch
402 {
403 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed HomeURI (this should never happen): {0}", aCircuit.ServiceURLs["HomeURI"]);
404 aCircuit.lastname = "@" + aCircuit.ServiceURLs["HomeURI"].ToString();
405 }
406 }
407  
408 //
409 // Finally launch the agent at the destination
410 //
411 Constants.TeleportFlags loginFlag = isFirstLogin ? Constants.TeleportFlags.ViaLogin : Constants.TeleportFlags.ViaHGLogin;
412  
413 // Preserve our TeleportFlags we have gathered so-far
414 loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags;
415  
416 m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0} {1}", aCircuit.Name, loginFlag);
417  
418 return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason);
419 }
420  
421 protected bool Authenticate(AgentCircuitData aCircuit)
422 {
423 if (!CheckAddress(aCircuit.ServiceSessionID))
424 return false;
425  
426 if (string.IsNullOrEmpty(aCircuit.IPAddress))
427 {
428 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide a client IP address.");
429 return false;
430 }
431  
432 string userURL = string.Empty;
433 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
434 userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
435  
436 if (userURL == string.Empty)
437 {
438 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide an authentication server URL");
439 return false;
440 }
441  
442 if (userURL == m_ExternalName)
443 {
444 return m_UserAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
445 }
446 else
447 {
448 IUserAgentService userAgentService = new UserAgentServiceConnector(userURL);
449  
450 try
451 {
452 return userAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
453 }
454 catch
455 {
456 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to contact authentication service at {0}", userURL);
457 return false;
458 }
459 }
460 }
461  
462 // Check that the service token was generated for *this* grid.
463 // If it wasn't then that's a fake agent.
464 protected bool CheckAddress(string serviceToken)
465 {
466 string[] parts = serviceToken.Split(new char[] { ';' });
467 if (parts.Length < 2)
468 return false;
469  
470 char[] trailing_slash = new char[] { '/' };
471 string addressee = parts[0].TrimEnd(trailing_slash);
472 string externalname = m_ExternalName.TrimEnd(trailing_slash);
473 m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
474  
475 Uri uri;
476 try
477 {
478 uri = new Uri(addressee);
479 }
480 catch
481 {
482 m_log.DebugFormat("[GATEKEEPER SERVICE]: Visitor provided malformed service address {0}", addressee);
483 return false;
484 }
485  
486 return string.Equals(uri.GetLeftPart(UriPartial.Authority), m_Uri.GetLeftPart(UriPartial.Authority), StringComparison.OrdinalIgnoreCase) ;
487 }
488  
489 #endregion
490  
491  
492 #region Misc
493  
494 private bool IsException(AgentCircuitData aCircuit, List<string> exceptions)
495 {
496 bool exception = false;
497 if (exceptions.Count > 0) // we have exceptions
498 {
499 // Retrieve the visitor's origin
500 string userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
501 if (!userURL.EndsWith("/"))
502 userURL += "/";
503  
504 if (exceptions.Find(delegate(string s)
505 {
506 if (!s.EndsWith("/"))
507 s += "/";
508 return s == userURL;
509 }) != null)
510 exception = true;
511 }
512  
513 return exception;
514 }
515  
516 #endregion
517 }
518 }