aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/HypergridService/UserAgentService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/HypergridService/UserAgentService.cs')
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs545
1 files changed, 545 insertions, 0 deletions
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs
new file mode 100644
index 0000000..398a7b7
--- /dev/null
+++ b/OpenSim/Services/HypergridService/UserAgentService.cs
@@ -0,0 +1,545 @@
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.Generic;
30using System.Net;
31using System.Reflection;
32
33using OpenSim.Framework;
34using OpenSim.Services.Connectors.Friends;
35using OpenSim.Services.Connectors.Hypergrid;
36using OpenSim.Services.Interfaces;
37using GridRegion = OpenSim.Services.Interfaces.GridRegion;
38using OpenSim.Server.Base;
39using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
40
41using OpenMetaverse;
42using log4net;
43using Nini.Config;
44
45namespace OpenSim.Services.HypergridService
46{
47 /// <summary>
48 /// This service is for HG1.5 only, to make up for the fact that clients don't
49 /// keep any private information in themselves, and that their 'home service'
50 /// needs to do it for them.
51 /// Once we have better clients, this shouldn't be needed.
52 /// </summary>
53 public class UserAgentService : IUserAgentService
54 {
55 private static readonly ILog m_log =
56 LogManager.GetLogger(
57 MethodBase.GetCurrentMethod().DeclaringType);
58
59 // This will need to go into a DB table
60 static Dictionary<UUID, TravelingAgentInfo> m_TravelingAgents = new Dictionary<UUID, TravelingAgentInfo>();
61
62 static bool m_Initialized = false;
63
64 protected static IGridUserService m_GridUserService;
65 protected static IGridService m_GridService;
66 protected static GatekeeperServiceConnector m_GatekeeperConnector;
67 protected static IGatekeeperService m_GatekeeperService;
68 protected static IFriendsService m_FriendsService;
69 protected static IPresenceService m_PresenceService;
70 protected static IUserAccountService m_UserAccountService;
71 protected static IFriendsSimConnector m_FriendsLocalSimConnector; // standalone, points to HGFriendsModule
72 protected static FriendsSimConnector m_FriendsSimConnector; // grid
73
74 protected static string m_GridName;
75
76 protected static bool m_BypassClientVerification;
77
78 public UserAgentService(IConfigSource config) : this(config, null)
79 {
80 }
81
82 public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector)
83 {
84 // Let's set this always, because we don't know the sequence
85 // of instantiations
86 if (friendsConnector != null)
87 m_FriendsLocalSimConnector = friendsConnector;
88
89 if (!m_Initialized)
90 {
91 m_Initialized = true;
92
93 m_log.DebugFormat("[HOME USERS SECURITY]: Starting...");
94
95 m_FriendsSimConnector = new FriendsSimConnector();
96
97 IConfig serverConfig = config.Configs["UserAgentService"];
98 if (serverConfig == null)
99 throw new Exception(String.Format("No section UserAgentService in config file"));
100
101 string gridService = serverConfig.GetString("GridService", String.Empty);
102 string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
103 string gatekeeperService = serverConfig.GetString("GatekeeperService", String.Empty);
104 string friendsService = serverConfig.GetString("FriendsService", String.Empty);
105 string presenceService = serverConfig.GetString("PresenceService", String.Empty);
106 string userAccountService = serverConfig.GetString("UserAccountService", String.Empty);
107
108 m_BypassClientVerification = serverConfig.GetBoolean("BypassClientVerification", false);
109
110 if (gridService == string.Empty || gridUserService == string.Empty || gatekeeperService == string.Empty)
111 throw new Exception(String.Format("Incomplete specifications, UserAgent Service cannot function."));
112
113 Object[] args = new Object[] { config };
114 m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
115 m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
116 m_GatekeeperConnector = new GatekeeperServiceConnector();
117 m_GatekeeperService = ServerUtils.LoadPlugin<IGatekeeperService>(gatekeeperService, args);
118 m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(friendsService, args);
119 m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
120 m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountService, args);
121
122 m_GridName = serverConfig.GetString("ExternalName", string.Empty);
123 if (m_GridName == string.Empty)
124 {
125 serverConfig = config.Configs["GatekeeperService"];
126 m_GridName = serverConfig.GetString("ExternalName", string.Empty);
127 }
128 if (!m_GridName.EndsWith("/"))
129 m_GridName = m_GridName + "/";
130 }
131 }
132
133 public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt)
134 {
135 position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY;
136
137 m_log.DebugFormat("[USER AGENT SERVICE]: Request to get home region of user {0}", userID);
138
139 GridRegion home = null;
140 GridUserInfo uinfo = m_GridUserService.GetGridUserInfo(userID.ToString());
141 if (uinfo != null)
142 {
143 if (uinfo.HomeRegionID != UUID.Zero)
144 {
145 home = m_GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
146 position = uinfo.HomePosition;
147 lookAt = uinfo.HomeLookAt;
148 }
149 if (home == null)
150 {
151 List<GridRegion> defs = m_GridService.GetDefaultRegions(UUID.Zero);
152 if (defs != null && defs.Count > 0)
153 home = defs[0];
154 }
155 }
156
157 return home;
158 }
159
160 public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason)
161 {
162 m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}",
163 agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI);
164 // Take the IP address + port of the gatekeeper (reg) plus the info of finalDestination
165 GridRegion region = new GridRegion(gatekeeper);
166 region.ServerURI = gatekeeper.ServerURI;
167 region.ExternalHostName = finalDestination.ExternalHostName;
168 region.InternalEndPoint = finalDestination.InternalEndPoint;
169 region.RegionName = finalDestination.RegionName;
170 region.RegionID = finalDestination.RegionID;
171 region.RegionLocX = finalDestination.RegionLocX;
172 region.RegionLocY = finalDestination.RegionLocY;
173
174 // Generate a new service session
175 agentCircuit.ServiceSessionID = region.ServerURI + ";" + UUID.Random();
176 TravelingAgentInfo old = UpdateTravelInfo(agentCircuit, region);
177
178 bool success = false;
179 string myExternalIP = string.Empty;
180 string gridName = gatekeeper.ServerURI;
181
182 m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName);
183
184 if (m_GridName == gridName)
185 success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason);
186 else
187 {
188 success = m_GatekeeperConnector.CreateAgent(region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, out myExternalIP, out reason);
189 if (success)
190 // Report them as nowhere
191 m_PresenceService.ReportAgent(agentCircuit.SessionID, UUID.Zero);
192 }
193
194 if (!success)
195 {
196 m_log.DebugFormat("[USER AGENT SERVICE]: Unable to login user {0} {1} to grid {2}, reason: {3}",
197 agentCircuit.firstname, agentCircuit.lastname, region.ServerURI, reason);
198
199 // restore the old travel info
200 lock (m_TravelingAgents)
201 {
202 if (old == null)
203 m_TravelingAgents.Remove(agentCircuit.SessionID);
204 else
205 m_TravelingAgents[agentCircuit.SessionID] = old;
206 }
207
208 return false;
209 }
210
211 m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP);
212 // else set the IP addresses associated with this client
213 if (clientIP != null)
214 m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString();
215 m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP;
216
217 return true;
218 }
219
220 public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, out string reason)
221 {
222 reason = string.Empty;
223 return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, null, out reason);
224 }
225
226 private void SetClientIP(UUID sessionID, string ip)
227 {
228 if (m_TravelingAgents.ContainsKey(sessionID))
229 {
230 m_log.DebugFormat("[USER AGENT SERVICE]: Setting IP {0} for session {1}", ip, sessionID);
231 m_TravelingAgents[sessionID].ClientIPAddress = ip;
232 }
233 }
234
235 TravelingAgentInfo UpdateTravelInfo(AgentCircuitData agentCircuit, GridRegion region)
236 {
237 TravelingAgentInfo travel = new TravelingAgentInfo();
238 TravelingAgentInfo old = null;
239 lock (m_TravelingAgents)
240 {
241 if (m_TravelingAgents.ContainsKey(agentCircuit.SessionID))
242 {
243 // Very important! Override whatever this agent comes with.
244 // UserAgentService always sets the IP for every new agent
245 // with the original IP address.
246 agentCircuit.IPAddress = m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress;
247
248 old = m_TravelingAgents[agentCircuit.SessionID];
249 }
250
251 m_TravelingAgents[agentCircuit.SessionID] = travel;
252 }
253 travel.UserID = agentCircuit.AgentID;
254 travel.GridExternalName = region.ServerURI;
255 travel.ServiceToken = agentCircuit.ServiceSessionID;
256 if (old != null)
257 travel.ClientIPAddress = old.ClientIPAddress;
258
259 return old;
260 }
261
262 public void LogoutAgent(UUID userID, UUID sessionID)
263 {
264 m_log.DebugFormat("[USER AGENT SERVICE]: User {0} logged out", userID);
265
266 lock (m_TravelingAgents)
267 {
268 List<UUID> travels = new List<UUID>();
269 foreach (KeyValuePair<UUID, TravelingAgentInfo> kvp in m_TravelingAgents)
270 if (kvp.Value == null) // do some clean up
271 travels.Add(kvp.Key);
272 else if (kvp.Value.UserID == userID)
273 travels.Add(kvp.Key);
274 foreach (UUID session in travels)
275 m_TravelingAgents.Remove(session);
276 }
277
278 GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(userID.ToString());
279 if (guinfo != null)
280 m_GridUserService.LoggedOut(userID.ToString(), sessionID, guinfo.LastRegionID, guinfo.LastPosition, guinfo.LastLookAt);
281 }
282
283 // We need to prevent foreign users with the same UUID as a local user
284 public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName)
285 {
286 if (!m_TravelingAgents.ContainsKey(sessionID))
287 return false;
288
289 TravelingAgentInfo travel = m_TravelingAgents[sessionID];
290
291 return travel.GridExternalName.ToLower() == thisGridExternalName.ToLower();
292 }
293
294 public bool VerifyClient(UUID sessionID, string reportedIP)
295 {
296 if (m_BypassClientVerification)
297 return true;
298
299 m_log.DebugFormat("[USER AGENT SERVICE]: Verifying Client session {0} with reported IP {1}.",
300 sessionID, reportedIP);
301
302 if (m_TravelingAgents.ContainsKey(sessionID))
303 {
304 m_log.DebugFormat("[USER AGENT SERVICE]: Comparing with login IP {0} and MyIP {1}",
305 m_TravelingAgents[sessionID].ClientIPAddress, m_TravelingAgents[sessionID].MyIpAddress);
306
307 return m_TravelingAgents[sessionID].ClientIPAddress == reportedIP ||
308 m_TravelingAgents[sessionID].MyIpAddress == reportedIP; // NATed
309 }
310
311 return false;
312 }
313
314 public bool VerifyAgent(UUID sessionID, string token)
315 {
316 if (m_TravelingAgents.ContainsKey(sessionID))
317 {
318 m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, m_TravelingAgents[sessionID].ServiceToken);
319 return m_TravelingAgents[sessionID].ServiceToken == token;
320 }
321
322 m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID);
323
324 return false;
325 }
326
327 public List<UUID> StatusNotification(List<string> friends, UUID foreignUserID, bool online)
328 {
329 if (m_FriendsService == null || m_PresenceService == null)
330 {
331 m_log.WarnFormat("[USER AGENT SERVICE]: Unable to perform status notifications because friends or presence services are missing");
332 return new List<UUID>();
333 }
334
335 List<UUID> localFriendsOnline = new List<UUID>();
336
337 m_log.DebugFormat("[USER AGENT SERVICE]: Status notification: foreign user {0} wants to notify {1} local friends", foreignUserID, friends.Count);
338
339 // First, let's double check that the reported friends are, indeed, friends of that user
340 // And let's check that the secret matches
341 List<string> usersToBeNotified = new List<string>();
342 foreach (string uui in friends)
343 {
344 UUID localUserID;
345 string secret = string.Empty, tmp = string.Empty;
346 if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret))
347 {
348 FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID);
349 foreach (FriendInfo finfo in friendInfos)
350 {
351 if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret))
352 {
353 // great!
354 usersToBeNotified.Add(localUserID.ToString());
355 }
356 }
357 }
358 }
359
360 // Now, let's send the notifications
361 m_log.DebugFormat("[USER AGENT SERVICE]: Status notification: user has {0} local friends", usersToBeNotified.Count);
362
363 // First, let's send notifications to local users who are online in the home grid
364 PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray());
365 if (friendSessions != null && friendSessions.Length > 0)
366 {
367 PresenceInfo friendSession = null;
368 foreach (PresenceInfo pinfo in friendSessions)
369 if (pinfo.RegionID != UUID.Zero) // let's guard against traveling agents
370 {
371 friendSession = pinfo;
372 break;
373 }
374
375 if (friendSession != null)
376 {
377 ForwardStatusNotificationToSim(friendSession.RegionID, foreignUserID, friendSession.UserID, online);
378 usersToBeNotified.Remove(friendSession.UserID.ToString());
379 UUID id;
380 if (UUID.TryParse(friendSession.UserID, out id))
381 localFriendsOnline.Add(id);
382
383 }
384 }
385
386 // Lastly, let's notify the rest who may be online somewhere else
387 foreach (string user in usersToBeNotified)
388 {
389 UUID id = new UUID(user);
390 if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName)
391 {
392 string url = m_TravelingAgents[id].GridExternalName;
393 // forward
394 m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url);
395 }
396 }
397
398 // and finally, let's send the online friends
399 if (online)
400 {
401 return localFriendsOnline;
402 }
403 else
404 return new List<UUID>();
405 }
406
407 protected void ForwardStatusNotificationToSim(UUID regionID, UUID foreignUserID, string user, bool online)
408 {
409 UUID userID;
410 if (UUID.TryParse(user, out userID))
411 {
412 if (m_FriendsLocalSimConnector != null)
413 {
414 m_log.DebugFormat("[USER AGENT SERVICE]: Local Notify, user {0} is {1}", foreignUserID, (online ? "online" : "offline"));
415 m_FriendsLocalSimConnector.StatusNotify(foreignUserID, userID, online);
416 }
417 else
418 {
419 GridRegion region = m_GridService.GetRegionByUUID(UUID.Zero /* !!! */, regionID);
420 if (region != null)
421 {
422 m_log.DebugFormat("[USER AGENT SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
423 m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID, online);
424 }
425 }
426 }
427 }
428
429 public List<UUID> GetOnlineFriends(UUID foreignUserID, List<string> friends)
430 {
431 List<UUID> online = new List<UUID>();
432
433 if (m_FriendsService == null || m_PresenceService == null)
434 {
435 m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get online friends because friends or presence services are missing");
436 return online;
437 }
438
439 m_log.DebugFormat("[USER AGENT SERVICE]: Foreign user {0} wants to know status of {1} local friends", foreignUserID, friends.Count);
440
441 // First, let's double check that the reported friends are, indeed, friends of that user
442 // And let's check that the secret matches and the rights
443 List<string> usersToBeNotified = new List<string>();
444 foreach (string uui in friends)
445 {
446 UUID localUserID;
447 string secret = string.Empty, tmp = string.Empty;
448 if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret))
449 {
450 FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID);
451 foreach (FriendInfo finfo in friendInfos)
452 {
453 if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret) &&
454 (finfo.TheirFlags & (int)FriendRights.CanSeeOnline) != 0 && (finfo.TheirFlags != -1))
455 {
456 // great!
457 usersToBeNotified.Add(localUserID.ToString());
458 }
459 }
460 }
461 }
462
463 // Now, let's find out their status
464 m_log.DebugFormat("[USER AGENT SERVICE]: GetOnlineFriends: user has {0} local friends with status rights", usersToBeNotified.Count);
465
466 // First, let's send notifications to local users who are online in the home grid
467 PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray());
468 if (friendSessions != null && friendSessions.Length > 0)
469 {
470 foreach (PresenceInfo pi in friendSessions)
471 {
472 UUID presenceID;
473 if (UUID.TryParse(pi.UserID, out presenceID))
474 online.Add(presenceID);
475 }
476 }
477
478 return online;
479 }
480
481 public Dictionary<string, object> GetServerURLs(UUID userID)
482 {
483 if (m_UserAccountService == null)
484 {
485 m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get server URLs because user account service is missing");
486 return new Dictionary<string, object>();
487 }
488 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero /*!!!*/, userID);
489 if (account != null)
490 return account.ServiceURLs;
491
492 return new Dictionary<string, object>();
493 }
494
495 public string LocateUser(UUID userID)
496 {
497 foreach (TravelingAgentInfo t in m_TravelingAgents.Values)
498 {
499 if (t == null)
500 {
501 m_log.ErrorFormat("[USER AGENT SERVICE]: Oops! Null TravelingAgentInfo. Please report this on mantis");
502 continue;
503 }
504 if (t.UserID == userID && !m_GridName.Equals(t.GridExternalName))
505 return t.GridExternalName;
506 }
507
508 return string.Empty;
509 }
510
511 public string GetUUI(UUID userID, UUID targetUserID)
512 {
513 // Let's see if it's a local user
514 UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, targetUserID);
515 if (account != null)
516 return targetUserID.ToString() + ";" + m_GridName + ";" + account.FirstName + " " + account.LastName ;
517
518 // Let's try the list of friends
519 FriendInfo[] friends = m_FriendsService.GetFriends(userID);
520 if (friends != null && friends.Length > 0)
521 {
522 foreach (FriendInfo f in friends)
523 if (f.Friend.StartsWith(targetUserID.ToString()))
524 {
525 // Let's remove the secret
526 UUID id; string tmp = string.Empty, secret = string.Empty;
527 if (Util.ParseUniversalUserIdentifier(f.Friend, out id, out tmp, out tmp, out tmp, out secret))
528 return f.Friend.Replace(secret, "0");
529 }
530 }
531
532 return string.Empty;
533 }
534 }
535
536 class TravelingAgentInfo
537 {
538 public UUID UserID;
539 public string GridExternalName = string.Empty;
540 public string ServiceToken = string.Empty;
541 public string ClientIPAddress = string.Empty; // as seen from this user agent service
542 public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper
543 }
544
545}