SEBWIN-322: Implemented service configuration infrastructure and windows update service deactivation.
This commit is contained in:
parent
0d793dd326
commit
9dece7e4ae
9 changed files with 388 additions and 50 deletions
|
@ -145,7 +145,7 @@ namespace SafeExamBrowser.Lockdown.UnitTests
|
|||
Thread.Sleep(25);
|
||||
sut.Stop();
|
||||
|
||||
backup.Verify(b => b.GetAllConfigurations(), Times.Exactly(counter));
|
||||
backup.Verify(b => b.GetAllConfigurations(), Times.Between(counter, counter + 1, Range.Inclusive));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
using System;
|
||||
using SafeExamBrowser.Contracts.Lockdown;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Lockdown.FeatureConfigurations;
|
||||
using SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive;
|
||||
using SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive;
|
||||
using SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown
|
||||
{
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using SafeExamBrowser.Contracts.Lockdown;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal abstract class ServiceConfiguration : FeatureConfiguration
|
||||
{
|
||||
private static readonly TimeSpan FIVE_SECONDS = TimeSpan.FromSeconds(5);
|
||||
private IList<ServiceDataItem> originalItems;
|
||||
|
||||
protected abstract IEnumerable<ServiceConfigurationItem> Items { get; }
|
||||
|
||||
public ServiceConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
originalItems = new List<ServiceDataItem>();
|
||||
}
|
||||
|
||||
public override bool DisableFeature()
|
||||
{
|
||||
var success = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
success &= TrySet(new ServiceDataItem { Name = item.Name, Status = item.Disabled });
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Info("Successfully disabled feature.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to disable feature!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public override bool EnableFeature()
|
||||
{
|
||||
var success = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
success &= TrySet(new ServiceDataItem { Name = item.Name, Status = item.Enabled });
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Info("Successfully enabled feature.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to enable feature!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public override FeatureConfigurationStatus GetStatus()
|
||||
{
|
||||
var status = FeatureConfigurationStatus.Undefined;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var current = ReadService(item.Name);
|
||||
|
||||
if (current.Status == item.Disabled && status != FeatureConfigurationStatus.Enabled)
|
||||
{
|
||||
status = FeatureConfigurationStatus.Disabled;
|
||||
}
|
||||
else if (current.Status == item.Enabled && status != FeatureConfigurationStatus.Disabled)
|
||||
{
|
||||
status = FeatureConfigurationStatus.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = FeatureConfigurationStatus.Undefined;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var original = ReadService(item.Name);
|
||||
|
||||
if (original.Status != ServiceStatus.NotAvailable)
|
||||
{
|
||||
originalItems.Add(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Restore()
|
||||
{
|
||||
foreach (var item in new List<ServiceDataItem>(originalItems))
|
||||
{
|
||||
if (TrySet(item))
|
||||
{
|
||||
originalItems.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
var success = !originalItems.Any();
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Info("Successfully restored feature.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to restore feature!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private ServiceDataItem ReadService(string name)
|
||||
{
|
||||
var item = new ServiceDataItem { Name = name, Status = ServiceStatus.NotAvailable };
|
||||
|
||||
try
|
||||
{
|
||||
using (var service = new ServiceController(name))
|
||||
{
|
||||
item.Status = ToStatus(service.Status);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to retrieve status of service '{name}'!", e);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private bool TrySet(ServiceDataItem item)
|
||||
{
|
||||
var success = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (IsAvailable(item))
|
||||
{
|
||||
using (var service = new ServiceController(item.Name))
|
||||
{
|
||||
if (item.Status == ServiceStatus.Running)
|
||||
{
|
||||
success = TryStart(service);
|
||||
}
|
||||
else if (item.Status == ServiceStatus.Stopped)
|
||||
{
|
||||
success = TryStop(service);
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Debug($"Successfully set service {item}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Could not set service {item}! Current status: {service.Status}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Cannot set service {item} as it does not exist!");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to set service {item}!", e);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TryStart(ServiceController service)
|
||||
{
|
||||
var success = true;
|
||||
|
||||
if (service.Status == ServiceControllerStatus.PausePending)
|
||||
{
|
||||
service.WaitForStatus(ServiceControllerStatus.Paused, FIVE_SECONDS);
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.Paused)
|
||||
{
|
||||
service.Continue();
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.Stopped)
|
||||
{
|
||||
service.Start();
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.StartPending || service.Status == ServiceControllerStatus.ContinuePending)
|
||||
{
|
||||
service.WaitForStatus(ServiceControllerStatus.Running, FIVE_SECONDS);
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.Running)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TryStop(ServiceController service)
|
||||
{
|
||||
var success = false;
|
||||
|
||||
if (service.Status == ServiceControllerStatus.Paused)
|
||||
{
|
||||
service.Continue();
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.StartPending || service.Status == ServiceControllerStatus.ContinuePending)
|
||||
{
|
||||
service.WaitForStatus(ServiceControllerStatus.Running, FIVE_SECONDS);
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.Running)
|
||||
{
|
||||
service.Stop();
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.StopPending)
|
||||
{
|
||||
service.WaitForStatus(ServiceControllerStatus.Stopped, FIVE_SECONDS);
|
||||
service.Refresh();
|
||||
}
|
||||
|
||||
if (service.Status == ServiceControllerStatus.Stopped)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool IsAvailable(ServiceDataItem item)
|
||||
{
|
||||
return ServiceController.GetServices().Any(s => s.ServiceName == item.Name);
|
||||
}
|
||||
|
||||
private ServiceStatus ToStatus(ServiceControllerStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case ServiceControllerStatus.ContinuePending:
|
||||
case ServiceControllerStatus.Running:
|
||||
case ServiceControllerStatus.StartPending:
|
||||
return ServiceStatus.Running;
|
||||
default:
|
||||
return ServiceStatus.Stopped;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations
|
||||
{
|
||||
internal class ServiceConfigurationItem
|
||||
{
|
||||
internal ServiceStatus Disabled { get; }
|
||||
internal ServiceStatus Enabled { get; }
|
||||
internal string Name { get; }
|
||||
|
||||
internal ServiceConfigurationItem(string name, ServiceStatus disabled, ServiceStatus enabled)
|
||||
{
|
||||
Disabled = disabled;
|
||||
Enabled = enabled;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal class ServiceDataItem
|
||||
{
|
||||
internal string Name { get; set; }
|
||||
internal ServiceStatus Status { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $@"'{Name}' => '{(Status == ServiceStatus.Running ? ServiceStatus.Running.ToString().ToLower() : ServiceStatus.Stopped.ToString().ToLower())}'";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations
|
||||
{
|
||||
internal enum ServiceStatus
|
||||
{
|
||||
NotAvailable,
|
||||
Running,
|
||||
Stopped
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal class WindowsUpdateConfiguration : ServiceConfiguration
|
||||
{
|
||||
protected override IEnumerable<ServiceConfigurationItem> Items => new []
|
||||
{
|
||||
new ServiceConfigurationItem("wuauserv", ServiceStatus.Stopped, ServiceStatus.Running)
|
||||
};
|
||||
|
||||
public WindowsUpdateConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Lockdown;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal class WindowsUpdateConfiguration : FeatureConfiguration
|
||||
{
|
||||
public WindowsUpdateConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool DisableFeature()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool EnableFeature()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override FeatureConfigurationStatus GetStatus()
|
||||
{
|
||||
return FeatureConfigurationStatus.Undefined;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override bool Restore()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,7 @@
|
|||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AutoRestoreMechanism.cs" />
|
||||
|
@ -74,7 +75,11 @@
|
|||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\LockWorkstationConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\MachineHive\SwitchUserConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\VmwareOverlayConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\WindowsUpdateConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\ServiceConfigurations\ServiceConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\ServiceConfigurations\ServiceConfigurationItem.cs" />
|
||||
<Compile Include="FeatureConfigurations\ServiceConfigurations\ServiceDataItem.cs" />
|
||||
<Compile Include="FeatureConfigurations\ServiceConfigurations\ServiceStatus.cs" />
|
||||
<Compile Include="FeatureConfigurations\ServiceConfigurations\WindowsUpdateConfiguration.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SystemConfigurationUpdate.cs" />
|
||||
</ItemGroup>
|
||||
|
|
Loading…
Add table
Reference in a new issue