From dbbbec48dfbc51f30953d8a46f4fc8f192bd277c Mon Sep 17 00:00:00 2001
From: Teravus Ovares
Date: Sun, 14 Sep 2008 18:39:17 +0000
Subject: * This update makes configuring SSL a little easier on Windows XP. 
 It also makes it possible to run a HTTPS server on the region.   It also has
 a junk Certification authority for test purposes. * There are still a lot of
 things that are hard coded to use http.   They need to be fixed. * Also
 includes directions * A standard junk PEM file to append to
 app_settings/CA.pem in the client so SSL will work

---
 OpenSim/Framework/NetworkServersInfo.cs            |   7 ++
 OpenSim/Framework/Servers/BaseHttpServer.cs        | 129 ++++++++++++++++++++-
 .../Region/ClientStack/RegionApplicationBase.cs    |   7 +-
 .../Modules/InterGrid/OpenGridProtocolModule.cs    |  57 ++++++++-
 4 files changed, 193 insertions(+), 7 deletions(-)

(limited to 'OpenSim')

diff --git a/OpenSim/Framework/NetworkServersInfo.cs b/OpenSim/Framework/NetworkServersInfo.cs
index 43ec11e..9f3014d 100644
--- a/OpenSim/Framework/NetworkServersInfo.cs
+++ b/OpenSim/Framework/NetworkServersInfo.cs
@@ -49,6 +49,9 @@ namespace OpenSim.Framework
         public string UserRecvKey = String.Empty;
         public string UserSendKey = String.Empty;
         public string UserURL = String.Empty;
+        public bool HttpUsesSSL = false;
+        public string HttpSSLCN = "";
+        public uint httpSSLPort = 9001;
 
 
         public NetworkServersInfo()
@@ -78,6 +81,10 @@ namespace OpenSim.Framework
 
             HttpListenerPort =
                 (uint) config.Configs["Network"].GetInt("http_listener_port", (int) DefaultHttpListenerPort);
+            httpSSLPort =
+                (uint)config.Configs["Network"].GetInt("http_listener_sslport", ((int)DefaultHttpListenerPort+1));
+            HttpUsesSSL = config.Configs["Network"].GetBoolean("http_listener_ssl", false);
+            HttpSSLCN = config.Configs["Network"].GetString("http_listener_cn", "");
             RemotingListenerPort =
                 (uint) config.Configs["Network"].GetInt("remoting_listener_port", (int) RemotingListenerPort);
             GridURL =
diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs
index 181eb92..6cf6744 100644
--- a/OpenSim/Framework/Servers/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/BaseHttpServer.cs
@@ -26,12 +26,14 @@
  */
 
 using System;
+using System.Diagnostics;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Net;
 using System.Net.Sockets;
 using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Threading;
 using System.Xml;
@@ -39,6 +41,7 @@ using OpenMetaverse.StructuredData;
 using log4net;
 using Nwc.XmlRpc;
 
+
 namespace OpenSim.Framework.Servers
 {
     public class BaseHttpServer
@@ -55,9 +58,14 @@ namespace OpenSim.Framework.Servers
         protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
 
         protected uint m_port;
+        protected uint m_sslport;
         protected bool m_ssl = false;
         protected bool m_firstcaps = true;
 
+        public uint SSLPort
+        {
+            get { return m_sslport; }
+        }
         public uint Port
         {
             get { return m_port; }
@@ -72,8 +80,124 @@ namespace OpenSim.Framework.Servers
         {
             m_ssl = ssl;
             m_port = port;
+            
+        }
+
+        public BaseHttpServer(uint port, bool ssl, uint sslport, string CN)
+        {
+            m_ssl = ssl;
+            m_port = port;
+            if (m_ssl)
+            {
+                bool result = SetupSsl((int)sslport, CN);
+                m_sslport = sslport;
+            }
+        }
+
+        
+        
+        public bool SetupSsl(int port, string CN)
+        {
+            string searchCN = Environment.MachineName.ToUpper();
+            
+            if (CN.Length > 0)
+                searchCN = CN.ToUpper();
+
+            Type t = Type.GetType("Mono.Runtime");
+            if (t != null)
+            {
+                // TODO Mono User Friendly HTTPS setup
+                // if this doesn't exist, then mono people can still manually use httpcfg
+            }
+            else
+            {
+                // Windows.
+                // Search through the store for a certificate with a Common name specified in OpenSim.ini.
+                // We need to find it's hash so we can pass it to httpcfg
+                X509Store store = new X509Store(StoreLocation.LocalMachine);
+                //Use the first cert to configure Ssl
+                store.Open(OpenFlags.ReadOnly);
+                //Assumption is we have certs. If not then this call will fail :(
+                try
+                {
+                    bool found = false;
+                    //X509Certificate2.CreateFromCertFile("testCert.cer");
+
+                    foreach (X509Certificate2 cert in store.Certificates)
+                    {
+                        String certHash = cert.GetCertHashString();
+                        //Only install certs issued for the machine and has the name as the machine name
+                        if (cert.Subject.ToUpper().IndexOf(searchCN) >= 0)
+                        {
+                            string httpcfgparams = String.Format("set ssl -i 0.0.0.0:{1} -c \"MY\" -h {0}", certHash, port);
+                            try
+                            {
+                                found = true;
+
+                                ExecuteHttpcfgCommand(httpcfgparams);
+ 
+                                break;
+                            }
+                            catch (Exception e)
+                            {
+                                m_log.WarnFormat("[HTTPS]: Automatic HTTPS setup failed.  Do you have httpcfg.exe in your path?  If not, you can download it in the windowsXP Service Pack 2 Support Tools, here: http://www.microsoft.com/downloads/details.aspx?FamilyID=49ae8576-9bb9-4126-9761-ba8011fabf38&displaylang=en.  When you get it installed type, httpcfg {0}", httpcfgparams);
+                                return false;
+                            }
+                        }
+                    }
+
+                    if (!found)
+                    {
+                        m_log.WarnFormat("[HTTPS]: We didn't find a certificate that matched the common name {0}.  Automatic HTTPS setup failed, you may have certificate errors.  To fix this, make sure you generate a certificate request(CSR) using OpenSSL or the IIS snap-in with the common name you specified in opensim.ini. Then get it signed by a certification authority or sign it yourself with OpenSSL and the junkCA.  Finally, be sure to import the cert to the 'MY' store(StoreLocation.LocalMachine)", searchCN);
+                        return false;
+                    }
+
+                }
+                catch (Exception e)
+                {
+                    m_log.WarnFormat("[HTTPS]: We didn't any certificates in your LocalMachine certificate store.  Automatic HTTPS setup failed, you may have certificate errors.  To fix this, make sure you generate a certificate request(CSR) using OpenSSL or the IIS snap-inwith the common name you specified in opensim.ini. Then get it signed by a certification authority or sign it yourself with OpenSSL and the junkCA.  Finally, be sure to import the cert to the 'MY' store(StoreLocation.LocalMachine). The configured common name is {0}", searchCN);
+                    return false;
+                }
+                finally
+                {
+                    if (store != null)
+                    {
+                        store.Close();
+                    }
+                }
+            }
+            return true;
         }
 
+        private void ExecuteHttpcfgCommand(string p)
+        {
+            
+            string file = "httpcfg";
+
+            ProcessStartInfo info = new ProcessStartInfo(file, p);
+            // Redirect output so we can read it.
+            info.RedirectStandardOutput = true;
+            // To redirect, we must not use shell execute.
+            info.UseShellExecute = false;
+
+            // Create and execute the process.
+            Process httpcfgprocess = Process.Start(info);
+            httpcfgprocess.Start();
+            string result = httpcfgprocess.StandardOutput.ReadToEnd();
+            if (result.Contains("HttpSetServiceConfiguration completed with"))
+            {
+                //success
+            
+            }
+            else
+            {
+                //fail
+                m_log.WarnFormat("[HTTPS]:Error binding certificate with the requested port.  Message:{0}", result);
+            }
+            
+        }
+
+
         /// <summary>
         /// Add a stream handler to the http server.  If the handler already exists, then nothing happens.
         /// </summary>
@@ -907,7 +1031,8 @@ namespace OpenSim.Framework.Servers
                 }
                 else
                 {
-                    m_httpListener.Prefixes.Add("https://+:" + m_port + "/");
+                    m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
+                    m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
                 }
                 m_httpListener.Start();
 
@@ -921,7 +1046,7 @@ namespace OpenSim.Framework.Servers
             catch (Exception e)
             {
                 m_log.Warn("[HTTPD]: Error - " + e.Message);
-                m_log.Warn("Tip: Do you have permission to listen on port " + m_port + "?");
+                m_log.Warn("Tip: Do you have permission to listen on port " + m_port + "," + m_sslport + "?");
             }
         }
 
diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
index 8bb35c1..469c084 100644
--- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs
+++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs
@@ -81,7 +81,12 @@ namespace OpenSim.Region.ClientStack
 
             Initialize();
 
-            m_httpServer = new BaseHttpServer(m_httpServerPort);
+            m_httpServer = new BaseHttpServer(m_httpServerPort,m_networkServersInfo.HttpUsesSSL,m_networkServersInfo.httpSSLPort, m_networkServersInfo.HttpSSLCN);
+            if (m_networkServersInfo.HttpUsesSSL && (m_networkServersInfo.HttpListenerPort == m_networkServersInfo.httpSSLPort))
+            {
+                m_log.Error("[HTTP]: HTTP Server config failed.   HTTP Server and HTTPS server must be on different ports");
+            }
+
 
             m_log.Info("[REGION]: Starting HTTP server");
 
diff --git a/OpenSim/Region/Environment/Modules/InterGrid/OpenGridProtocolModule.cs b/OpenSim/Region/Environment/Modules/InterGrid/OpenGridProtocolModule.cs
index 6e37b95..68f35e8 100644
--- a/OpenSim/Region/Environment/Modules/InterGrid/OpenGridProtocolModule.cs
+++ b/OpenSim/Region/Environment/Modules/InterGrid/OpenGridProtocolModule.cs
@@ -86,6 +86,9 @@ namespace OpenSim.Region.Environment.Modules.InterGrid
         private Dictionary<UUID, OGPState> m_OGPState = new Dictionary<UUID, OGPState>();
         private string LastNameSuffix = "_EXTERNAL";
         private string FirstNamePrefix = "";
+        private string httpsCN = "";
+        private bool httpSSL = false;
+        private uint httpsslport = 0;
 
         #region IRegionModule Members
 
@@ -93,6 +96,7 @@ namespace OpenSim.Region.Environment.Modules.InterGrid
         {
             bool enabled = false;
             IConfig cfg = null;
+            IConfig httpcfg = null;
             try
             {
                 cfg = config.Configs["OpenGridProtocol"];
@@ -100,6 +104,16 @@ namespace OpenSim.Region.Environment.Modules.InterGrid
             {
                 enabled = false;
             }
+
+            try
+            {
+                httpcfg = config.Configs["Network"];
+            }
+            catch (NullReferenceException)
+            {
+               
+            }
+
             if (cfg != null)
             {
                 enabled = cfg.GetBoolean("ogp_enabled", false);
@@ -139,6 +153,20 @@ namespace OpenSim.Region.Environment.Modules.InterGrid
                     }
                 }
             }
+            lock (m_scene)
+            {
+                if (m_scene.Count == 1)
+                {
+                    if (httpcfg != null)
+                    {
+                        httpSSL = httpcfg.GetBoolean("http_listener_ssl", false);
+                        httpsCN = httpcfg.GetString("http_listener_cn", scene.RegionInfo.ExternalHostName);
+                        if (httpsCN.Length == 0)
+                            httpsCN = scene.RegionInfo.ExternalHostName;
+                        httpsslport = (uint)httpcfg.GetInt("http_listener_sslport",((int)scene.RegionInfo.HttpPort + 1));
+                    }
+                }
+            }
             // Of interest to this module potentially
             //scene.EventManager.OnNewClient += OnNewClient;
             //scene.EventManager.OnGridInstantMessageToFriendsModule += OnGridInstantMessage;
@@ -371,14 +399,35 @@ namespace OpenSim.Region.Environment.Modules.InterGrid
             // Get a reference to the user's cap so we can pull out the Caps Object Path
             OpenSim.Framework.Communications.Capabilities.Caps userCap = homeScene.GetCapsHandlerForUser(agentData.AgentID);
 
+            string rezHttpProtocol = "http://";
+            string regionCapsHttpProtocol = "http://";
+            string httpaddr = reg.ExternalHostName;
+            string urlport = reg.HttpPort.ToString();
+
+
+            if (httpSSL)
+            {
+                rezHttpProtocol = "https://";
+
+                urlport = httpsslport.ToString();
+
+                if (httpsCN.Length > 0)
+                    httpaddr = httpsCN;
+            }
+            
+
+            // Be warned that the two following lines assume http not 
+            // https since region caps are not implemented in https currently
+
             // DEPRECIATED
-            responseMap["seed_capability"] = LLSD.FromString("http://" + reg.ExternalHostName + ":" + reg.HttpPort + "/CAPS/" + userCap.CapsObjectPath + "0000/");
+            responseMap["seed_capability"] = LLSD.FromString(regionCapsHttpProtocol + httpaddr + ":" + reg.HttpPort + "/CAPS/" + userCap.CapsObjectPath + "0000/");
             
             // REPLACEMENT
-            responseMap["region_seed_capability"] = LLSD.FromString("http://" + reg.ExternalHostName + ":" + reg.HttpPort + "/CAPS/" + userCap.CapsObjectPath + "0000/");
+            responseMap["region_seed_capability"] = LLSD.FromString(regionCapsHttpProtocol + httpaddr + ":" + reg.HttpPort + "/CAPS/" + userCap.CapsObjectPath + "0000/");
+
             
-            responseMap["rez_avatar/rez"] = LLSD.FromString("http://" + reg.ExternalHostName + ":" + reg.HttpPort + rezAvatarPath);
-            responseMap["rez_avatar/derez"] = LLSD.FromString("http://" + reg.ExternalHostName + ":" + reg.HttpPort + derezAvatarPath);
+            responseMap["rez_avatar/rez"] = LLSD.FromString(rezHttpProtocol + httpaddr + ":" + urlport + rezAvatarPath);
+            responseMap["rez_avatar/derez"] = LLSD.FromString(rezHttpProtocol + httpaddr + ":" + urlport + derezAvatarPath);
 
             // Add the user to the list of CAPS that are outstanding.
             // well allow the caps hosts in this dictionary
-- 
cgit v1.1