Make the Serverconfig request admin rights only if required

This commit is contained in:
Flamefire committed 2014-03-11 00:42:22 +01:00
1 parent 070777eb68
commit 0a9c6e5cfe
5 files changed
+206 -71

No files matched your search

+5 -5
View File
@@ -142,14 +142,14 @@ namespace ServerLib
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);*/
_RegisterUrlAndCert(_BaseAddress.Port);
_RegisterUrlAndCert(_BaseAddress.Port, false);
_Host.Open();
}
catch (CommunicationException e)
{
if (e is AddressAccessDeniedException || e is AddressAlreadyInUseException)
{
_RegisterUrlAndCert(_BaseAddress.Port);
_RegisterUrlAndCert(_BaseAddress.Port, true);
try
{
_Host.Abort();
@@ -178,18 +178,18 @@ namespace ServerLib
}
}
private void _RegisterUrlAndCert(int port)
private void _RegisterUrlAndCert(int port, bool reserve)
{
#if WIN
ProcessStartInfo info = new ProcessStartInfo
{
FileName = "VocaluxeServerConfig.exe",
Arguments = port + " " + (_Encrypted ? "true" : "false"),
WorkingDirectory = Environment.CurrentDirectory,
Arguments = port + " " + (_Encrypted ? "true" : "false") + (reserve ? " reserve" : ""),
UseShellExecute = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
Verb = "runas"
};
Process p = Process.Start(info);
p.WaitForExit();
+2
View File
@@ -259,6 +259,7 @@ namespace Vocaluxe
Environment.Exit(Environment.ExitCode);
}
#if !DEBUG
[HandleProcessCorruptedStateExceptions]
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{
@@ -273,6 +274,7 @@ namespace Vocaluxe
CLog.LogError("Unhandled exception: " + e.Message + stackTrace);
_CloseProgram();
}
#endif
private static Assembly _AssemblyResolver(Object sender, ResolveEventArgs args)
{
+155 -49
View File
@@ -15,6 +15,9 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System.Diagnostics;
using System.Security.Authentication;
using System.Security.Principal;
using Security.Cryptography;
using Security.Cryptography.X509Certificates;
using System;
@@ -26,34 +29,64 @@ using NetFwTypeLib;
namespace WebserverInitalConfig
{
public static class CConfigHttpApi
public class CConfigHttpApi
{
// ReSharper disable InconsistentNaming
private const String CLSID_NetFwMgr = "{304CE942-6E39-40D8-943A-B913C40C9CD4}";
private const String CLSID_NetAuthApp = "{EC9846B3-2762-4A6B-A214-6ACB603462D2}";
private const String CLSID_NetOpenPort = "{0CA545C6-37AD-4A6C-BF92-9F7610067EF5}";
private const string _AppGUID = "{7baf41f1-48b7-42cb-b145-f815499cb48f}";
// ReSharper restore InconsistentNaming
public static void ReserveUrl(string networkString)
private readonly string _RuleName;
private readonly string _ExePath;
private readonly string _IP;
private readonly int _Port;
private readonly bool _IsTCP;
public CConfigHttpApi(string ruleName, string exePath, string ip, int port, bool isTCP)
{
_ExePath = exePath;
_Port = port;
_IsTCP = isTCP;
_IP = ip;
_RuleName = ruleName;
}
private static void _ReserveUrl(string networkString)
{
if (!IsAdministrator())
throw new AuthenticationException();
HttpApi.ReserveURL(networkString, "D:(A;;GX;;;S-1-1-0)");
}
public static void BindCert(string ip, int port, X509Certificate2 cert)
public void ReserveUrl()
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ip), port);
if (HttpApi.QuerySslCertificateInfo(endpoint) != null)
HttpApi.DeleteCertificateBinding(endpoint);
HttpApi.BindCertificate(endpoint, cert.GetCertHash(), StoreName.My, new Guid("{7baf41f1-48b7-42cb-b145-f815499cb48f}"));
_ReserveUrl("https://+:" + _Port + "/");
}
public static void AddCertToStore(X509Certificate2 cert)
private void _BindCert(X509Certificate cert)
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(_IP), _Port);
HttpApi.SslCertificateInfo certificateInfo = HttpApi.QuerySslCertificateInfo(endpoint);
if (certificateInfo != null && !certificateInfo.Hash.SequenceEqual(cert.GetCertHash()))
{
if (!IsAdministrator())
throw new AuthenticationException();
HttpApi.DeleteCertificateBinding(endpoint);
HttpApi.BindCertificate(endpoint, cert.GetCertHash(), StoreName.My, new Guid(_AppGUID));
}
}
private static void _AddCertToStore(X509Certificate2 cert)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
X509Certificate2Collection oldCerts = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName,
cert.SubjectName.Name, false);
// ReSharper disable AssignNullToNotNullAttribute
X509Certificate2Collection oldCerts = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, cert.SubjectName.Name, false);
// ReSharper restore AssignNullToNotNullAttribute
foreach (X509Certificate2 oldCert in oldCerts)
store.Remove(oldCert);
@@ -62,7 +95,25 @@ namespace WebserverInitalConfig
store.Close();
}
public static X509Certificate2 GetSelfSignedCert(string subjectName)
private static X509Certificate2 _GetCert(string name)
{
X509Certificate2 result = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var name2 = new X500DistinguishedName(name);
// ReSharper disable AssignNullToNotNullAttribute
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, name2.Name, false);
// ReSharper restore AssignNullToNotNullAttribute
if (certs.Count > 0)
result = certs[0];
store.Close();
return result;
}
private X509Certificate2 _GetSelfSignedCert(string subjectName)
{
var keyParam = new CngKeyCreationParameters
{
@@ -91,58 +142,113 @@ namespace WebserverInitalConfig
byte[] rawData = key.CreateSelfSignedCertificate(param).Export(X509ContentType.Pfx, "");
var cert = new X509Certificate2(rawData, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet)
{
FriendlyName = "Vocaluxe Server Certificate"
FriendlyName = _RuleName + " Server Certificate"
};
return cert;
}
private static void _AddFirewallRuleForProfile(INetFwProfile profile, string exePath, int port, bool isTCP)
public void CreateAndAddCert(string hostName)
{
bool isFirewallEnabled = profile.FirewallEnabled;
string certName = "CN=" + hostName + ", C=DE, O=" + _RuleName + ", OU=" + _RuleName + " Server";
if (!isFirewallEnabled)
return;
INetFwAuthorizedApplications applications = profile.AuthorizedApplications;
if (!(from INetFwAuthorizedApplication a in applications
where a.ProcessImageFileName == exePath
select a).Any())
X509Certificate2 cert = _GetCert(certName);
if (cert == null)
{
INetFwAuthorizedApplication application = (INetFwAuthorizedApplication)Activator.CreateInstance(
Type.GetTypeFromCLSID(new Guid(CLSID_NetAuthApp)));
application.Name = "Vocaluxe";
application.ProcessImageFileName = exePath;
application.Enabled = true;
application.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
applications.Add(application);
}
INetFwOpenPorts openPorts = profile.GloballyOpenPorts;
NET_FW_IP_PROTOCOL_ protocol = isTCP ? NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP : NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP;
if (!(from INetFwOpenPort p in openPorts
where (p.Port == port &&
(p.Protocol == protocol))
select p).Any())
{
INetFwOpenPort openPort = (INetFwOpenPort)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID_NetOpenPort)));
openPort.Enabled = true;
openPort.Port = port;
openPort.Protocol = protocol;
openPort.Name = "Vocaluxe(" + port + ")";
openPort.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
openPorts.Add(openPort);
if (!IsAdministrator())
throw new AuthenticationException();
cert = _GetSelfSignedCert(certName);
_AddCertToStore(cert);
}
_BindCert(cert);
}
public static void AddFirewallRule(string exePath, int port, bool isTCP)
private bool _IsAppAuthorized(INetFwProfile profile)
{
if (!profile.FirewallEnabled)
return true;
foreach (INetFwAuthorizedApplication a in profile.AuthorizedApplications)
{
if (a.ProcessImageFileName == _ExePath)
return true;
}
return false;
}
private bool _IsPortOpen(INetFwProfile profile)
{
NET_FW_IP_PROTOCOL_ protocol = _GetProtocol();
if (!profile.FirewallEnabled)
return true;
foreach (INetFwOpenPort p in profile.GloballyOpenPorts)
{
if (p.Protocol == protocol && p.Port == _Port)
return true;
}
return false;
}
private NET_FW_IP_PROTOCOL_ _GetProtocol()
{
return _IsTCP ? NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP : NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_UDP;
}
private void _AddFirewallRuleForProfile(INetFwProfile profile)
{
bool isAppAuthorized = _IsAppAuthorized(profile);
bool isPortOpen = _IsPortOpen(profile);
if ((!isAppAuthorized || !isPortOpen) && !IsAdministrator())
throw new AuthenticationException();
if (!isAppAuthorized)
_AddAppToFirewall(profile);
if (!isPortOpen)
_AddPortToFirewall(profile);
}
private void _AddPortToFirewall(INetFwProfile profile)
{
INetFwOpenPort openPort = (INetFwOpenPort)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID_NetOpenPort)));
openPort.Enabled = true;
openPort.Port = _Port;
openPort.Protocol = _GetProtocol();
openPort.Name = _RuleName + "(" + _Port + ")";
openPort.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
profile.GloballyOpenPorts.Add(openPort);
}
private void _AddAppToFirewall(INetFwProfile profile)
{
INetFwAuthorizedApplication application = (INetFwAuthorizedApplication)Activator.CreateInstance(
Type.GetTypeFromCLSID(new Guid(CLSID_NetAuthApp)));
application.Name = _RuleName;
application.ProcessImageFileName = _ExePath;
application.Enabled = true;
application.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
profile.AuthorizedApplications.Add(application);
}
public static bool IsAdministrator()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
// ReSharper disable AssignNullToNotNullAttribute
WindowsPrincipal principal = new WindowsPrincipal(identity);
// ReSharper restore AssignNullToNotNullAttribute
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
public void AddFirewallRule()
{
INetFwMgr manage = (INetFwMgr)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID_NetFwMgr)));
//AddFirewallRuleForProfile(manage.LocalPolicy.CurrentProfile, exePath, port, isTCP);
//_AddFirewallRuleForProfile(manage.LocalPolicy.CurrentProfile);
//if (manage.CurrentProfileType != NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD)
//Add to Home/Work(Private) and current net
//TODO: This somewhow adds 2 entries each instead of only one that is activated for Home/Work and public nets
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD), exePath, port, isTCP);
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_CURRENT), exePath, port, isTCP);
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD));
_AddFirewallRuleForProfile(manage.LocalPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_CURRENT));
}
/*public static X509Certificate2 getCert(string subject)
+44 -14
View File
@@ -16,34 +16,64 @@
#endregion
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Mime;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace WebserverInitalConfig
{
class Program
static class CProgram
{
// ReSharper disable InconsistentNaming
private static void Main(string[] args)
// ReSharper restore InconsistentNaming
{
if (args.Length != 2)
int port;
if (args.Length < 2 || !int.TryParse(args[0], out port))
{
Console.WriteLine("Usage: VocaluxeServerConfig port isHttps");
Environment.Exit(-1);
}
CConfigHttpApi.AddFirewallRule(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Vocaluxe.exe"), Int32.Parse(args[0]), true);
if (args[1].ToLower() == "true")
{
string hostname = Dns.GetHostName();
X509Certificate2 cert = CConfigHttpApi.GetSelfSignedCert("CN=" + hostname + " C=DE O=Vocaluxe OU=Vocaluxe Server");
CConfigHttpApi.AddCertToStore(cert);
CConfigHttpApi.BindCert("0.0.0.0", Int32.Parse(args[0]), cert);
CConfigHttpApi.ReserveUrl("https://+:" + args[0] + "/");
}
else
CConfigHttpApi.ReserveUrl("http://+:" + args[0] + "/");
{
CConfigHttpApi config = new CConfigHttpApi("Vocaluxe", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Vocaluxe.exe"), "0.0.0.0", port, true);
try
{
config.AddFirewallRule();
if (args[1].ToLower() == "true")
config.CreateAndAddCert(Dns.GetHostName());
if ((args.Length >= 3 && args[2] == "reserve") || CConfigHttpApi.IsAdministrator())
config.ReserveUrl();
}
catch (AuthenticationException)
{
ProcessStartInfo proc = new ProcessStartInfo
{
UseShellExecute = true,
WorkingDirectory = Environment.CurrentDirectory,
FileName = Process.GetCurrentProcess().MainModule.FileName,
Arguments = args[0] + " " + args[1],
Verb = "runas",
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
};
try
{
Process.Start(proc);
}
catch
{
// The user refused the elevation.
// Do nothing and return directly ...
Environment.Exit(-1);
}
}
}
}
}
}
@@ -32,9 +32,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Vocaluxe.ico</ApplicationIcon>
</PropertyGroup>