Restore SEBPatch
This commit is contained in:
164
SafeExamBrowser.Lockdown/AutoRestoreMechanism.cs
Normal file
164
SafeExamBrowser.Lockdown/AutoRestoreMechanism.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Threading.Tasks;
|
||||
using SafeExamBrowser.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown
|
||||
{
|
||||
public class AutoRestoreMechanism : IAutoRestoreMechanism
|
||||
{
|
||||
private readonly object @lock = new object();
|
||||
|
||||
private IFeatureConfigurationBackup backup;
|
||||
private ILogger logger;
|
||||
private ISystemConfigurationUpdate systemConfigurationUpdate;
|
||||
private bool running;
|
||||
private int timeout_ms;
|
||||
|
||||
public AutoRestoreMechanism(
|
||||
IFeatureConfigurationBackup backup,
|
||||
ILogger logger,
|
||||
ISystemConfigurationUpdate systemConfigurationUpdate,
|
||||
int timeout_ms)
|
||||
{
|
||||
if (timeout_ms < 0)
|
||||
{
|
||||
throw new ArgumentException("Must be 0 or greater!", nameof(timeout_ms));
|
||||
}
|
||||
|
||||
this.backup = backup;
|
||||
this.logger = logger;
|
||||
this.systemConfigurationUpdate = systemConfigurationUpdate;
|
||||
this.timeout_ms = timeout_ms;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
if (!running)
|
||||
{
|
||||
running = true;
|
||||
Task.Run(new Action(AutoRestore));
|
||||
logger.Info("Started auto-restore mechanism.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("Auto-restore mechanism is already running.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
running = false;
|
||||
logger.Info("Stopped auto-restore mechanism.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("Auto-restore mechanism is not running.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoRestore()
|
||||
{
|
||||
if (IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var configurations = backup.GetAllConfigurations();
|
||||
|
||||
if (configurations.Any())
|
||||
{
|
||||
var success = TryRestoreAll(configurations);
|
||||
|
||||
if (success == true)
|
||||
{
|
||||
systemConfigurationUpdate.ExecuteAsync();
|
||||
}
|
||||
else if (success == false)
|
||||
{
|
||||
Task.Delay(timeout_ms).ContinueWith((_) => AutoRestore());
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("Auto-restore mechanism was aborted.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
running = false;
|
||||
logger.Info("Nothing to restore, stopped auto-restore mechanism.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsStopped()
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
return !running;
|
||||
}
|
||||
}
|
||||
|
||||
private bool? TryRestoreAll(IList<IFeatureConfiguration> configurations)
|
||||
{
|
||||
var restored = 0;
|
||||
|
||||
logger.Info($"Attempting to restore {configurations.Count} items...");
|
||||
|
||||
foreach (var configuration in configurations)
|
||||
{
|
||||
var success = TryRestore(configuration);
|
||||
|
||||
if (success)
|
||||
{
|
||||
restored++;
|
||||
}
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info($"Restored {restored} of {configurations.Count} items.");
|
||||
|
||||
return restored == configurations.Count;
|
||||
}
|
||||
|
||||
private bool TryRestore(IFeatureConfiguration configuration)
|
||||
{
|
||||
var success = configuration.Restore();
|
||||
|
||||
if (success)
|
||||
{
|
||||
backup.Delete(configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Failed to restore {configuration}!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
140
SafeExamBrowser.Lockdown/FeatureConfigurationBackup.cs
Normal file
140
SafeExamBrowser.Lockdown/FeatureConfigurationBackup.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using SafeExamBrowser.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown
|
||||
{
|
||||
public class FeatureConfigurationBackup : IFeatureConfigurationBackup
|
||||
{
|
||||
private readonly object @lock = new object();
|
||||
|
||||
private string filePath;
|
||||
private IModuleLogger logger;
|
||||
|
||||
public FeatureConfigurationBackup(string filePath, IModuleLogger logger)
|
||||
{
|
||||
this.filePath = filePath;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void Delete(IFeatureConfiguration configuration)
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
var configurations = LoadFromFile();
|
||||
var obsolete = configurations.Find(c => c.Id == configuration.Id);
|
||||
|
||||
if (obsolete != default(IFeatureConfiguration))
|
||||
{
|
||||
configurations.Remove(obsolete);
|
||||
SaveToFile(configurations);
|
||||
logger.Info($"Successfully removed {configuration} from backup.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Could not delete {configuration} as it does not exist in backup!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IList<IFeatureConfiguration> GetAllConfigurations()
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
return LoadFromFile();
|
||||
}
|
||||
}
|
||||
|
||||
public IList<IFeatureConfiguration> GetBy(Guid groupId)
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
return LoadFromFile().Where(c => c.GroupId == groupId).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(IFeatureConfiguration configuration)
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
var configurations = LoadFromFile();
|
||||
|
||||
configurations.Add(configuration);
|
||||
SaveToFile(configurations);
|
||||
logger.Info($"Successfully added {configuration} to backup.");
|
||||
}
|
||||
}
|
||||
|
||||
private List<IFeatureConfiguration> LoadFromFile()
|
||||
{
|
||||
var configurations = new List<IFeatureConfiguration>();
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
var context = new StreamingContext(StreamingContextStates.All, logger);
|
||||
|
||||
logger.Debug($"Attempting to load backup data from '{filePath}'...");
|
||||
|
||||
using (var stream = File.Open(filePath, FileMode.Open))
|
||||
{
|
||||
configurations = (List<IFeatureConfiguration>) new BinaryFormatter(null, context).Deserialize(stream);
|
||||
}
|
||||
|
||||
logger.Debug($"Backup data successfully loaded, found {configurations.Count} items.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Debug($"No backup data found under '{filePath}'.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to load backup data from '{filePath}'!", e);
|
||||
}
|
||||
|
||||
return configurations;
|
||||
}
|
||||
|
||||
private void SaveToFile(List<IFeatureConfiguration> configurations)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (configurations.Any())
|
||||
{
|
||||
logger.Debug($"Attempting to save backup data to '{filePath}'...");
|
||||
|
||||
using (var stream = File.Open(filePath, FileMode.Create))
|
||||
{
|
||||
new BinaryFormatter().Serialize(stream, configurations);
|
||||
}
|
||||
|
||||
logger.Debug($"Successfully saved {configurations.Count} items.");
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Delete(filePath);
|
||||
logger.Debug("No backup data to save, deleted backup file.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to save backup data to '{filePath}'!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
119
SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs
Normal file
119
SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive;
|
||||
using SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive;
|
||||
using SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown
|
||||
{
|
||||
public class FeatureConfigurationFactory : IFeatureConfigurationFactory
|
||||
{
|
||||
private readonly IModuleLogger logger;
|
||||
|
||||
public FeatureConfigurationFactory(IModuleLogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public IList<IFeatureConfiguration> CreateAll(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new List<IFeatureConfiguration>
|
||||
{
|
||||
CreateChangePasswordConfiguration(groupId, sid, userName),
|
||||
CreateChromeNotificationConfiguration(groupId, sid, userName),
|
||||
CreateEaseOfAccessConfiguration(groupId),
|
||||
CreateFindPrinterConfiguration(groupId, sid, userName),
|
||||
CreateLockWorkstationConfiguration(groupId, sid, userName),
|
||||
CreateMachinePowerOptionsConfiguration(groupId),
|
||||
CreateNetworkOptionsConfiguration(groupId),
|
||||
CreateRemoteConnectionConfiguration(groupId),
|
||||
CreateSignoutConfiguration(groupId, sid, userName),
|
||||
CreateSwitchUserConfiguration(groupId),
|
||||
CreateTaskManagerConfiguration(groupId, sid, userName),
|
||||
CreateUserPowerOptionsConfiguration(groupId, sid, userName),
|
||||
CreateVmwareOverlayConfiguration(groupId, sid, userName),
|
||||
CreateWindowsUpdateConfiguration(groupId)
|
||||
};
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateChangePasswordConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new ChangePasswordConfiguration(groupId, logger.CloneFor(nameof(ChangePasswordConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateChromeNotificationConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new ChromeNotificationConfiguration(groupId, logger.CloneFor(nameof(ChromeNotificationConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateEaseOfAccessConfiguration(Guid groupId)
|
||||
{
|
||||
return new EaseOfAccessConfiguration(groupId, logger.CloneFor(nameof(EaseOfAccessConfiguration)));
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateFindPrinterConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new FindPrinterConfiguration(groupId, logger.CloneFor(nameof(FindPrinterConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateLockWorkstationConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new LockWorkstationConfiguration(groupId, logger.CloneFor(nameof(LockWorkstationConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateMachinePowerOptionsConfiguration(Guid groupId)
|
||||
{
|
||||
return new MachinePowerOptionsConfiguration(groupId, logger.CloneFor(nameof(MachinePowerOptionsConfiguration)));
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateNetworkOptionsConfiguration(Guid groupId)
|
||||
{
|
||||
return new NetworkOptionsConfiguration(groupId, logger.CloneFor(nameof(NetworkOptionsConfiguration)));
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateRemoteConnectionConfiguration(Guid groupId)
|
||||
{
|
||||
return new RemoteConnectionConfiguration(groupId, logger.CloneFor(nameof(RemoteConnectionConfiguration)));
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateSignoutConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new SignoutConfiguration(groupId, logger.CloneFor(nameof(SignoutConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateSwitchUserConfiguration(Guid groupId)
|
||||
{
|
||||
return new SwitchUserConfiguration(groupId, logger.CloneFor(nameof(SwitchUserConfiguration)));
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateTaskManagerConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new TaskManagerConfiguration(groupId, logger.CloneFor(nameof(TaskManagerConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateUserPowerOptionsConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new UserPowerOptionsConfiguration(groupId, logger.CloneFor(nameof(UserPowerOptionsConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateVmwareOverlayConfiguration(Guid groupId, string sid, string userName)
|
||||
{
|
||||
return new VmwareOverlayConfiguration(groupId, logger.CloneFor(nameof(VmwareOverlayConfiguration)), sid, userName);
|
||||
}
|
||||
|
||||
public IFeatureConfiguration CreateWindowsUpdateConfiguration(Guid groupId)
|
||||
{
|
||||
return new WindowsUpdateConfiguration(groupId, logger.CloneFor(nameof(WindowsUpdateConfiguration)));
|
||||
}
|
||||
}
|
||||
}
|
148
SafeExamBrowser.Lockdown/FeatureConfigurationMonitor.cs
Normal file
148
SafeExamBrowser.Lockdown/FeatureConfigurationMonitor.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Threading.Tasks;
|
||||
using SafeExamBrowser.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown
|
||||
{
|
||||
public class FeatureConfigurationMonitor : IFeatureConfigurationMonitor
|
||||
{
|
||||
private readonly object @lock = new object();
|
||||
|
||||
private IDictionary<IFeatureConfiguration, FeatureConfigurationStatus> configurations;
|
||||
private ILogger logger;
|
||||
private readonly int timeout_ms;
|
||||
private bool running;
|
||||
|
||||
public FeatureConfigurationMonitor(ILogger logger, int timeout_ms)
|
||||
{
|
||||
if (timeout_ms < 0)
|
||||
{
|
||||
throw new ArgumentException("Must be 0 or greater!", nameof(timeout_ms));
|
||||
}
|
||||
|
||||
this.configurations = new Dictionary<IFeatureConfiguration, FeatureConfigurationStatus>();
|
||||
this.logger = logger;
|
||||
this.timeout_ms = timeout_ms;
|
||||
}
|
||||
|
||||
public void Observe(IFeatureConfiguration configuration, FeatureConfigurationStatus status)
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
configurations.Add(configuration, status);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
running = false;
|
||||
configurations.Clear();
|
||||
logger.Info("Stopped monitoring.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("Monitoring is not running.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
if (!running)
|
||||
{
|
||||
running = true;
|
||||
Task.Run(new Action(Monitor));
|
||||
logger.Info("Started monitoring.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("Monitoring is already running.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Monitor()
|
||||
{
|
||||
if (IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var configurations = new Dictionary<IFeatureConfiguration, FeatureConfigurationStatus>(this.configurations);
|
||||
|
||||
logger.Debug($"Checking {configurations.Count} configurations...");
|
||||
|
||||
foreach (var item in configurations)
|
||||
{
|
||||
var configuration = item.Key;
|
||||
var status = item.Value;
|
||||
|
||||
Enforce(configuration, status);
|
||||
|
||||
if (IsStopped())
|
||||
{
|
||||
logger.Info("Monitoring was aborted.");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (configurations.Any())
|
||||
{
|
||||
Task.Delay(timeout_ms).ContinueWith((_) => Monitor());
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
running = false;
|
||||
logger.Info("Nothing to be monitored, stopped monitoring.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Enforce(IFeatureConfiguration configuration, FeatureConfigurationStatus status)
|
||||
{
|
||||
var currentStatus = configuration.GetStatus();
|
||||
|
||||
if (currentStatus != status)
|
||||
{
|
||||
logger.Warn($"{configuration} is {currentStatus.ToString().ToLower()} instead of {status.ToString().ToLower()}!");
|
||||
|
||||
if (status == FeatureConfigurationStatus.Disabled)
|
||||
{
|
||||
configuration.DisableFeature();
|
||||
}
|
||||
else if (status == FeatureConfigurationStatus.Enabled)
|
||||
{
|
||||
configuration.EnableFeature();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsStopped()
|
||||
{
|
||||
lock (@lock)
|
||||
{
|
||||
return !running;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Runtime.Serialization;
|
||||
using SafeExamBrowser.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal abstract class FeatureConfiguration : IFeatureConfiguration
|
||||
{
|
||||
[NonSerialized]
|
||||
protected ILogger logger;
|
||||
|
||||
public Guid Id { get; }
|
||||
public Guid GroupId { get; }
|
||||
|
||||
public FeatureConfiguration(Guid groupId, ILogger logger)
|
||||
{
|
||||
this.GroupId = groupId;
|
||||
this.Id = Guid.NewGuid();
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public abstract bool DisableFeature();
|
||||
public abstract bool EnableFeature();
|
||||
public abstract FeatureConfigurationStatus GetStatus();
|
||||
public abstract void Initialize();
|
||||
public abstract bool Reset();
|
||||
public abstract bool Restore();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{GetType().Name} ({Id})";
|
||||
}
|
||||
|
||||
[OnDeserialized]
|
||||
private void OnDeserializedMethod(StreamingContext context)
|
||||
{
|
||||
logger = (context.Context as IModuleLogger).CloneFor(GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive
|
||||
{
|
||||
/// <summary>
|
||||
/// Controls whether the ease of access option is available on the Security / Login Screen of the operating system. See also
|
||||
/// https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-embedded-embeddedlogon-brandingneutral.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class EaseOfAccessConfiguration : MachineHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new[]
|
||||
{
|
||||
new RegistryConfigurationItem(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Embedded\EmbeddedLogon", "BrandingNeutral", 8, 0),
|
||||
new RegistryConfigurationItem(@"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Utilman.exe", "Debugger", "SebDummy.exe", "")
|
||||
};
|
||||
|
||||
public EaseOfAccessConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 Microsoft.Win32;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive
|
||||
{
|
||||
[Serializable]
|
||||
internal abstract class MachineHiveConfiguration : RegistryConfiguration
|
||||
{
|
||||
protected override RegistryKey RootKey => Registry.LocalMachine;
|
||||
|
||||
public MachineHiveConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool IsHiveAvailable(RegistryDataItem item)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class MachinePowerOptionsConfiguration : MachineHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem(@"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "NoClose", 1, 0)
|
||||
};
|
||||
|
||||
public MachinePowerOptionsConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class NetworkOptionsConfiguration : MachineHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem(@"HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\System", "DontDisplayNetworkSelectionUI", 1, 0)
|
||||
};
|
||||
|
||||
public NetworkOptionsConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies whether Remote Desktop connections are enabled.
|
||||
///
|
||||
/// See https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-terminalservices-localsessionmanager-fdenytsconnections:
|
||||
/// 0 = Specifies that remote desktop connections are enabled.
|
||||
/// 1 = Specifies that remote desktop connections are denied. This is the default value.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class RemoteConnectionConfiguration : MachineHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new[]
|
||||
{
|
||||
new RegistryConfigurationItem(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server", "fDenyTSConnections", 1, 0)
|
||||
};
|
||||
|
||||
public RemoteConnectionConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DisableFeature();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class SwitchUserConfiguration : MachineHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem(@"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System", "HideFastUserSwitching", 1, 0)
|
||||
};
|
||||
|
||||
public SwitchUserConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 Microsoft.Win32;
|
||||
using SafeExamBrowser.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal abstract class RegistryConfiguration : FeatureConfiguration
|
||||
{
|
||||
private IList<RegistryDataItem> itemsToDelete;
|
||||
private IList<RegistryDataItem> itemsToRestore;
|
||||
|
||||
protected abstract IEnumerable<RegistryConfigurationItem> Items { get; }
|
||||
protected abstract RegistryKey RootKey { get; }
|
||||
|
||||
public RegistryConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
|
||||
{
|
||||
itemsToDelete = new List<RegistryDataItem>();
|
||||
itemsToRestore = new List<RegistryDataItem>();
|
||||
}
|
||||
|
||||
protected abstract bool IsHiveAvailable(RegistryDataItem item);
|
||||
|
||||
public override bool DisableFeature()
|
||||
{
|
||||
var success = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
success &= TrySet(new RegistryDataItem { Key = item.Key, Value = item.Value, Data = 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 RegistryDataItem { Key = item.Key, Value = item.Value, Data = item.Enabled });
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Info("Successfully enabled feature.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to enable feature!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var original = ReadItem(item.Key, item.Value);
|
||||
|
||||
if (original.Data == null)
|
||||
{
|
||||
itemsToDelete.Add(original);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemsToRestore.Add(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override FeatureConfigurationStatus GetStatus()
|
||||
{
|
||||
var status = FeatureConfigurationStatus.Undefined;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var current = ReadItem(item.Key, item.Value);
|
||||
|
||||
if (current.Data?.Equals(item.Disabled) == true && status != FeatureConfigurationStatus.Enabled)
|
||||
{
|
||||
status = FeatureConfigurationStatus.Disabled;
|
||||
}
|
||||
else if (current.Data?.Equals(item.Enabled) == true && status != FeatureConfigurationStatus.Disabled)
|
||||
{
|
||||
status = FeatureConfigurationStatus.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = FeatureConfigurationStatus.Undefined;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
public override bool Restore()
|
||||
{
|
||||
foreach (var item in new List<RegistryDataItem>(itemsToDelete))
|
||||
{
|
||||
if (TryDelete(item))
|
||||
{
|
||||
itemsToDelete.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in new List<RegistryDataItem>(itemsToRestore))
|
||||
{
|
||||
if (TrySet(item))
|
||||
{
|
||||
itemsToRestore.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
var success = !itemsToDelete.Any() && !itemsToRestore.Any();
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Info("Successfully restored feature.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to restore feature!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
protected bool DeleteConfiguration()
|
||||
{
|
||||
var success = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
success &= TryDelete(new RegistryDataItem { Key = item.Key, Value = item.Value });
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
logger.Info("Successfully deleted feature configuration.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn("Failed to delete feature configuration!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private RegistryDataItem ReadItem(string key, string value)
|
||||
{
|
||||
var data = Registry.GetValue(key, value, null);
|
||||
var original = new RegistryDataItem { Key = key, Value = value, Data = data };
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
private bool TryDelete(RegistryDataItem item)
|
||||
{
|
||||
var success = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (IsHiveAvailable(item))
|
||||
{
|
||||
var keyWithoutRoot = item.Key.Substring(item.Key.IndexOf('\\') + 1);
|
||||
|
||||
using (var key = RootKey.OpenSubKey(keyWithoutRoot, true))
|
||||
{
|
||||
if (key.GetValue(item.Value) != null)
|
||||
{
|
||||
key.DeleteValue(item.Value);
|
||||
logger.Debug($"Successfully deleted registry item {item}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Debug($"No need to delete registry item {item} as it does not exist.");
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Cannot delete item {item} as its registry hive is not available!");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to delete registry item {item}!", e);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TrySet(RegistryDataItem item)
|
||||
{
|
||||
var success = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (IsHiveAvailable(item))
|
||||
{
|
||||
Registry.SetValue(item.Key, item.Value, item.Data);
|
||||
logger.Debug($"Successfully set registry item {item}.");
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Cannot set item {item} as its registry hive is not available!");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to set registry item {item}!", e);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.RegistryConfigurations
|
||||
{
|
||||
internal class RegistryConfigurationItem
|
||||
{
|
||||
internal object Disabled { get; }
|
||||
internal object Enabled { get; }
|
||||
internal string Key { get; }
|
||||
internal string Value { get; }
|
||||
|
||||
internal RegistryConfigurationItem(string key, string value, object disabled, object enabled)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
Disabled = disabled;
|
||||
Enabled = enabled;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.RegistryConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal class RegistryDataItem
|
||||
{
|
||||
internal object Data { get; set; }
|
||||
internal string Key { get; set; }
|
||||
internal string Value { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $@"'{Key}\{Value}'{(Data != null ? $" => '{Data}'" : "")}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class ChangePasswordConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Microsoft\Windows\CurrentVersion\Policies\System", "DisableChangePassword", 1, 0)
|
||||
};
|
||||
|
||||
public ChangePasswordConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
/// <summary>
|
||||
/// IMPORTANT: This registry configuration only has an effect after Chrome is restarted!
|
||||
///
|
||||
/// See https://www.chromium.org/administrators/policy-list-3#DefaultNotificationsSetting:
|
||||
/// • 1 = Allow sites to show desktop notifications.
|
||||
/// • 2 = Do not allow any site to show desktop notifications.
|
||||
/// • 3 = Ask every time a site wants to show desktop notifications.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class ChromeNotificationConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Policies\Google\Chrome", "DefaultNotificationsSetting", 2, 1)
|
||||
};
|
||||
|
||||
public ChromeNotificationConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class FindPrinterConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new[]
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "NoAddPrinter", 1, 0)
|
||||
};
|
||||
|
||||
public FindPrinterConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class LockWorkstationConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Microsoft\Windows\CurrentVersion\Policies\System", "DisableLockWorkstation", 1, 0)
|
||||
};
|
||||
|
||||
public LockWorkstationConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class SignoutConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "NoLogoff", 1, 0)
|
||||
};
|
||||
|
||||
public SignoutConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class TaskManagerConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Microsoft\Windows\CurrentVersion\Policies\System", "DisableTaskMgr", 1, 0)
|
||||
};
|
||||
|
||||
public TaskManagerConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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 Microsoft.Win32;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal abstract class UserHiveConfiguration : RegistryConfiguration
|
||||
{
|
||||
protected string SID { get; }
|
||||
protected string UserName { get; }
|
||||
|
||||
protected override RegistryKey RootKey => Registry.Users;
|
||||
|
||||
public UserHiveConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger)
|
||||
{
|
||||
SID = sid ?? throw new ArgumentNullException(nameof(sid));
|
||||
UserName = userName ?? throw new ArgumentNullException(nameof(userName));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{GetType().Name} ({Id}) for user '{UserName}'";
|
||||
}
|
||||
|
||||
protected override bool IsHiveAvailable(RegistryDataItem item)
|
||||
{
|
||||
var isAvailable = false;
|
||||
|
||||
try
|
||||
{
|
||||
isAvailable = Registry.Users.OpenSubKey(SID) != null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to check availability of registry hive for item {item}!", e);
|
||||
}
|
||||
|
||||
return isAvailable;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class UserPowerOptionsConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new[]
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "NoClose", 1, 0)
|
||||
};
|
||||
|
||||
public UserPowerOptionsConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return DeleteConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.UserHive
|
||||
{
|
||||
[Serializable]
|
||||
internal class VmwareOverlayConfiguration : UserHiveConfiguration
|
||||
{
|
||||
protected override IEnumerable<RegistryConfigurationItem> Items => new []
|
||||
{
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\VMware, Inc.\VMware VDM\Client", "EnableShade", 0, 1),
|
||||
new RegistryConfigurationItem($@"HKEY_USERS\{SID}\Software\Policies\VMware, Inc.\VMware VDM\Client", "EnableShade", "False", "True")
|
||||
};
|
||||
|
||||
public VmwareOverlayConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return EnableFeature();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations
|
||||
{
|
||||
[Serializable]
|
||||
internal abstract class ServiceConfiguration : FeatureConfiguration
|
||||
{
|
||||
private static readonly TimeSpan FIVE_SECONDS = TimeSpan.FromSeconds(5);
|
||||
private const int MAX_ATTEMPTS = 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 &= TrySetWithRetry(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 &= TrySetWithRetry(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 (TrySetWithRetry(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 TrySetWithRetry(ServiceDataItem item)
|
||||
{
|
||||
var success = false;
|
||||
|
||||
if (IsAvailable(item))
|
||||
{
|
||||
for (var attempt = 1; attempt <= MAX_ATTEMPTS && !success; attempt++)
|
||||
{
|
||||
logger.Debug($"Attempt {attempt}/{MAX_ATTEMPTS} to set service {item}...");
|
||||
success = TrySet(item);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
logger.Error($"All attempts to set service {item} have failed!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"Cannot set service {item} as it does not exist!");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TrySet(ServiceDataItem item)
|
||||
{
|
||||
var success = false;
|
||||
|
||||
try
|
||||
{
|
||||
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}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to set service {item}!", e);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TryStart(ServiceController service)
|
||||
{
|
||||
var success = false;
|
||||
|
||||
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)
|
||||
{
|
||||
var available = false;
|
||||
|
||||
try
|
||||
{
|
||||
available = ServiceController.GetServices().Any(s => s.ServiceName == item.Name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to check whether service '{item.Name}' is available!", e);
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
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) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Logging.Contracts;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Reset()
|
||||
{
|
||||
return EnableFeature();
|
||||
}
|
||||
}
|
||||
}
|
35
SafeExamBrowser.Lockdown/Properties/AssemblyInfo.cs
Normal file
35
SafeExamBrowser.Lockdown/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SafeExamBrowser.Lockdown")]
|
||||
[assembly: AssemblyDescription("Safe Exam Browser")]
|
||||
[assembly: AssemblyCompany("ETH Zürich")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Lockdown")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024 ETH Zürich, IT Services")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: InternalsVisibleTo("SafeExamBrowser.Lockdown.UnitTests")]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("386b6042-3e12-4753-9fc6-c88ea4f97030")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("1.0.0.0")]
|
102
SafeExamBrowser.Lockdown/SafeExamBrowser.Lockdown.csproj
Normal file
102
SafeExamBrowser.Lockdown/SafeExamBrowser.Lockdown.csproj
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{386B6042-3E12-4753-9FC6-C88EA4F97030}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Lockdown</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Lockdown</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AutoRestoreMechanism.cs" />
|
||||
<Compile Include="FeatureConfigurationFactory.cs" />
|
||||
<Compile Include="FeatureConfigurationBackup.cs" />
|
||||
<Compile Include="FeatureConfigurationMonitor.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\RegistryDataItem.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\RegistryConfigurationItem.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\ChromeNotificationConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\FeatureConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\MachineHive\MachineHiveConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\RegistryConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\FindPrinterConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\UserPowerOptionsConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\UserHiveConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\TaskManagerConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\MachineHive\EaseOfAccessConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\MachineHive\NetworkOptionsConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\ChangePasswordConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\MachineHive\MachinePowerOptionsConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\MachineHive\RemoteConnectionConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\SignoutConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\LockWorkstationConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\MachineHive\SwitchUserConfiguration.cs" />
|
||||
<Compile Include="FeatureConfigurations\RegistryConfigurations\UserHive\VmwareOverlayConfiguration.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>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Lockdown.Contracts\SafeExamBrowser.Lockdown.Contracts.csproj">
|
||||
<Project>{3368b17d-6060-4482-9983-aa800d74041d}</Project>
|
||||
<Name>SafeExamBrowser.Lockdown.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">
|
||||
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
|
||||
<Name>SafeExamBrowser.Logging.Contracts</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
59
SafeExamBrowser.Lockdown/SystemConfigurationUpdate.cs
Normal file
59
SafeExamBrowser.Lockdown/SystemConfigurationUpdate.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using SafeExamBrowser.Lockdown.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Lockdown
|
||||
{
|
||||
public class SystemConfigurationUpdate : ISystemConfigurationUpdate
|
||||
{
|
||||
private ILogger logger;
|
||||
|
||||
public SystemConfigurationUpdate(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
logger.Info("Starting system configuration update...");
|
||||
|
||||
var process = Process.Start(new ProcessStartInfo("cmd.exe", "/c \"gpupdate /force\"")
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false
|
||||
});
|
||||
|
||||
logger.Info("Waiting for update to complete...");
|
||||
process.WaitForExit();
|
||||
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
var lines = output.Split(new [] { Environment.NewLine, "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
logger.Info($"Update has completed: {String.Join(" ", lines.Skip(1))}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to update system configuration!", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteAsync()
|
||||
{
|
||||
Task.Run(new Action(Execute));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user