clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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, UUID agentID, string agentHomeURI, out string message)
208 {
209 m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to get hyperlink region {0} for user {1}{2}",
210 regionID, agentID, (agentHomeURI == null) ? "" : " @ " + agentHomeURI);
211  
212 message = null;
213  
214 if (!m_AllowTeleportsToAnyRegion)
215 {
216 // Don't even check the given regionID
217 message = "Teleporting to the default region.";
218 return m_DefaultGatewayRegion;
219 }
220  
221 GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID);
222  
223 if (region == null)
224 {
225 message = "The teleport destination could not be found.";
226 return null;
227 }
228  
229 return region;
230 }
231  
232 #region Login Agent
233 public bool LoginAgent(GridRegion source, AgentCircuitData aCircuit, GridRegion destination, out string reason)
234 {
235 reason = string.Empty;
236  
237 string authURL = string.Empty;
238 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
239 authURL = aCircuit.ServiceURLs["HomeURI"].ToString();
240  
241 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}. From region {11}",
242 aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionID,
243 aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, (TeleportFlags)aCircuit.teleportFlags,
244 (source == null) ? "Unknown" : string.Format("{0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI));
245  
246 string curViewer = Util.GetViewerName(aCircuit);
247  
248 //
249 // Check client
250 //
251 if (m_AllowedClients != string.Empty)
252 {
253 Regex arx = new Regex(m_AllowedClients);
254 Match am = arx.Match(curViewer);
255  
256 if (!am.Success)
257 {
258 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", curViewer);
259 return false;
260 }
261 }
262  
263 if (m_DeniedClients != string.Empty)
264 {
265 Regex drx = new Regex(m_DeniedClients);
266 Match dm = drx.Match(curViewer);
267  
268 if (dm.Success)
269 {
270 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", curViewer);
271 return false;
272 }
273 }
274  
275 //
276 // Authenticate the user
277 //
278 if (!Authenticate(aCircuit))
279 {
280 reason = "Unable to verify identity";
281 m_log.InfoFormat("[GATEKEEPER SERVICE]: Unable to verify identity of agent {0} {1}. Refusing service.", aCircuit.firstname, aCircuit.lastname);
282 return false;
283 }
284 m_log.DebugFormat("[GATEKEEPER SERVICE]: Identity verified for {0} {1} @ {2}", aCircuit.firstname, aCircuit.lastname, authURL);
285  
286 //
287 // Check for impersonations
288 //
289 UserAccount account = null;
290 if (m_UserAccountService != null)
291 {
292 // Check to see if we have a local user with that UUID
293 account = m_UserAccountService.GetUserAccount(m_ScopeID, aCircuit.AgentID);
294 if (account != null)
295 {
296 // Make sure this is the user coming home, and not a foreign user with same UUID as a local user
297 if (m_UserAgentService != null)
298 {
299 if (!m_UserAgentService.IsAgentComingHome(aCircuit.SessionID, m_ExternalName))
300 {
301 // Can't do, sorry
302 reason = "Unauthorized";
303 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agent {0} {1} has same ID as local user. Refusing service.",
304 aCircuit.firstname, aCircuit.lastname);
305 return false;
306  
307 }
308 }
309 }
310 }
311  
312 //
313 // Foreign agents allowed? Exceptions?
314 //
315 if (account == null)
316 {
317 bool allowed = m_ForeignAgentsAllowed;
318  
319 if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
320 allowed = false;
321  
322 if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
323 allowed = true;
324  
325 if (!allowed)
326 {
327 reason = "Destination does not allow visitors from your world";
328 m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1} @ {2}. Refusing service.",
329 aCircuit.firstname, aCircuit.lastname, aCircuit.ServiceURLs["HomeURI"]);
330 return false;
331 }
332 }
333  
334 //
335 // Is the user banned?
336 // This uses a Ban service that's more powerful than the configs
337 //
338 string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit));
339 if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL))
340 {
341 reason = "You are banned from this world";
342 m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui);
343 return false;
344 }
345  
346 m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name);
347  
348 bool isFirstLogin = false;
349 //
350 // Login the presence, if it's not there yet (by the login service)
351 //
352 PresenceInfo presence = m_PresenceService.GetAgent(aCircuit.SessionID);
353 if (presence != null) // it has been placed there by the login service
354 isFirstLogin = true;
355  
356 else
357 {
358 if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
359 {
360 reason = "Unable to login presence";
361 m_log.InfoFormat("[GATEKEEPER SERVICE]: Presence login failed for foreign agent {0} {1}. Refusing service.",
362 aCircuit.firstname, aCircuit.lastname);
363 return false;
364 }
365  
366 m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name);
367  
368 // Also login foreigners with GridUser service
369 if (m_GridUserService != null && account == null)
370 {
371 string userId = aCircuit.AgentID.ToString();
372 string first = aCircuit.firstname, last = aCircuit.lastname;
373 if (last.StartsWith("@"))
374 {
375 string[] parts = aCircuit.firstname.Split('.');
376 if (parts.Length >= 2)
377 {
378 first = parts[0];
379 last = parts[1];
380 }
381 }
382  
383 userId += ";" + aCircuit.ServiceURLs["HomeURI"] + ";" + first + " " + last;
384 m_GridUserService.LoggedIn(userId);
385 }
386 }
387  
388 //
389 // Get the region
390 //
391 destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID);
392 if (destination == null)
393 {
394 reason = "Destination region not found";
395 return false;
396 }
397  
398 m_log.DebugFormat(
399 "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name);
400  
401 //
402 // Adjust the visible name
403 //
404 if (account != null)
405 {
406 aCircuit.firstname = account.FirstName;
407 aCircuit.lastname = account.LastName;
408 }
409 if (account == null)
410 {
411 if (!aCircuit.lastname.StartsWith("@"))
412 aCircuit.firstname = aCircuit.firstname + "." + aCircuit.lastname;
413 try
414 {
415 Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString());
416 aCircuit.lastname = "@" + uri.Host; // + ":" + uri.Port;
417 }
418 catch
419 {
420 m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed HomeURI (this should never happen): {0}", aCircuit.ServiceURLs["HomeURI"]);
421 aCircuit.lastname = "@" + aCircuit.ServiceURLs["HomeURI"].ToString();
422 }
423 }
424  
425 //
426 // Finally launch the agent at the destination
427 //
428 Constants.TeleportFlags loginFlag = isFirstLogin ? Constants.TeleportFlags.ViaLogin : Constants.TeleportFlags.ViaHGLogin;
429  
430 // Preserve our TeleportFlags we have gathered so-far
431 loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags;
432  
433 m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0}, Teleport Flags: {1}", aCircuit.Name, loginFlag);
434  
435 string version;
436  
437 if (!m_SimulationService.QueryAccess(
438 destination, aCircuit.AgentID, aCircuit.ServiceURLs["HomeURI"].ToString(),
439 true, aCircuit.startpos, "SIMULATION/0.3", out version, out reason))
440 return false;
441  
442 return m_SimulationService.CreateAgent(source, destination, aCircuit, (uint)loginFlag, out reason);
443 }
444  
445 protected bool Authenticate(AgentCircuitData aCircuit)
446 {
447 if (!CheckAddress(aCircuit.ServiceSessionID))
448 return false;
449  
450 if (string.IsNullOrEmpty(aCircuit.IPAddress))
451 {
452 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide a client IP address.");
453 return false;
454 }
455  
456 string userURL = string.Empty;
457 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
458 userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
459  
460 if (userURL == string.Empty)
461 {
462 m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide an authentication server URL");
463 return false;
464 }
465  
466 if (userURL == m_ExternalName)
467 {
468 return m_UserAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
469 }
470 else
471 {
472 IUserAgentService userAgentService = new UserAgentServiceConnector(userURL);
473  
474 try
475 {
476 return userAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID);
477 }
478 catch
479 {
480 m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to contact authentication service at {0}", userURL);
481 return false;
482 }
483 }
484 }
485  
486 // Check that the service token was generated for *this* grid.
487 // If it wasn't then that's a fake agent.
488 protected bool CheckAddress(string serviceToken)
489 {
490 string[] parts = serviceToken.Split(new char[] { ';' });
491 if (parts.Length < 2)
492 return false;
493  
494 char[] trailing_slash = new char[] { '/' };
495 string addressee = parts[0].TrimEnd(trailing_slash);
496 string externalname = m_ExternalName.TrimEnd(trailing_slash);
497 m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname);
498  
499 Uri uri;
500 try
501 {
502 uri = new Uri(addressee);
503 }
504 catch
505 {
506 m_log.DebugFormat("[GATEKEEPER SERVICE]: Visitor provided malformed service address {0}", addressee);
507 return false;
508 }
509  
510 return string.Equals(uri.GetLeftPart(UriPartial.Authority), m_Uri.GetLeftPart(UriPartial.Authority), StringComparison.OrdinalIgnoreCase) ;
511 }
512  
513 #endregion
514  
515  
516 #region Misc
517  
518 private bool IsException(AgentCircuitData aCircuit, List<string> exceptions)
519 {
520 bool exception = false;
521 if (exceptions.Count > 0) // we have exceptions
522 {
523 // Retrieve the visitor's origin
524 string userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
525 if (!userURL.EndsWith("/"))
526 userURL += "/";
527  
528 if (exceptions.Find(delegate(string s)
529 {
530 if (!s.EndsWith("/"))
531 s += "/";
532 return s == userURL;
533 }) != null)
534 exception = true;
535 }
536  
537 return exception;
538 }
539  
540 #endregion
541 }
542 }