diff --git a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs
index d2153b4d..6d935905 100644
--- a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs
+++ b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfiguration.cs
@@ -45,6 +45,11 @@ namespace SafeExamBrowser.Contracts.Lockdown
///
void Initialize();
+ ///
+ /// Resets the feature to its default configuration. Returns true if successful, otherwise false.
+ ///
+ bool Reset();
+
///
/// Restores the feature to its previous configuration (i.e. before it was enabled or disabled). Returns true if successful,
/// otherwise false.
diff --git a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs
index 0e2dfb7c..92a2d009 100644
--- a/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs
+++ b/SafeExamBrowser.Contracts/Lockdown/IFeatureConfigurationFactory.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.Collections.Generic;
namespace SafeExamBrowser.Contracts.Lockdown
{
@@ -15,6 +16,11 @@ namespace SafeExamBrowser.Contracts.Lockdown
///
public interface IFeatureConfigurationFactory
{
+ ///
+ /// Creates all feature configurations.
+ ///
+ IList CreateAll(Guid groupId, string sid, string userName);
+
///
/// Creates an to control the option to change the password of a user account via the security screen.
///
diff --git a/SafeExamBrowser.Contracts/SystemComponents/IUserInfo.cs b/SafeExamBrowser.Contracts/SystemComponents/IUserInfo.cs
index a19ffd88..25aad530 100644
--- a/SafeExamBrowser.Contracts/SystemComponents/IUserInfo.cs
+++ b/SafeExamBrowser.Contracts/SystemComponents/IUserInfo.cs
@@ -22,5 +22,10 @@ namespace SafeExamBrowser.Contracts.SystemComponents
/// Retrieves the security identifier of the currently logged in user.
///
string GetUserSid();
+
+ ///
+ /// Tries to retrieve the security identifier for the specified user name. Returns true if successful, otherwise false.
+ ///
+ bool TryGetSidForUser(string userName, out string sid);
}
}
diff --git a/SafeExamBrowser.Lockdown.UnitTests/FeatureConfigurationStub.cs b/SafeExamBrowser.Lockdown.UnitTests/FeatureConfigurationStub.cs
index 9339a815..bfc6f9bb 100644
--- a/SafeExamBrowser.Lockdown.UnitTests/FeatureConfigurationStub.cs
+++ b/SafeExamBrowser.Lockdown.UnitTests/FeatureConfigurationStub.cs
@@ -42,6 +42,11 @@ namespace SafeExamBrowser.Lockdown.UnitTests
throw new NotImplementedException();
}
+ public bool Reset()
+ {
+ throw new NotImplementedException();
+ }
+
public bool Restore()
{
throw new NotImplementedException();
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs b/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs
index 4c05055b..906e2f0f 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurationFactory.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.Collections.Generic;
using SafeExamBrowser.Contracts.Lockdown;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive;
@@ -24,6 +25,25 @@ namespace SafeExamBrowser.Lockdown
this.logger = logger;
}
+ public IList CreateAll(Guid groupId, string sid, string userName)
+ {
+ return new List
+ {
+ CreateChangePasswordConfiguration(groupId, sid, userName),
+ CreateChromeNotificationConfiguration(groupId, sid, userName),
+ CreateEaseOfAccessConfiguration(groupId),
+ CreateLockWorkstationConfiguration(groupId, sid, userName),
+ CreateNetworkOptionsConfiguration(groupId),
+ CreatePowerOptionsConfiguration(groupId),
+ CreateRemoteConnectionConfiguration(groupId),
+ CreateSignoutConfiguration(groupId, sid, userName),
+ CreateSwitchUserConfiguration(groupId),
+ CreateTaskManagerConfiguration(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);
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs
index c2b2ab3a..ae325b18 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/FeatureConfiguration.cs
@@ -33,6 +33,7 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations
public abstract bool EnableFeature();
public abstract FeatureConfigurationStatus GetStatus();
public abstract void Initialize();
+ public abstract bool Reset();
public abstract bool Restore();
public override string ToString()
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/EaseOfAccessConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/EaseOfAccessConfiguration.cs
index 376b4590..33c55541 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/EaseOfAccessConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/EaseOfAccessConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public EaseOfAccessConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/NetworkOptionsConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/NetworkOptionsConfiguration.cs
index 8cdcc163..fdeda09e 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/NetworkOptionsConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/NetworkOptionsConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public NetworkOptionsConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/PowerOptionsConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/PowerOptionsConfiguration.cs
index 042fcb6a..eb7d7652 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/PowerOptionsConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/PowerOptionsConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public PowerOptionsConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/RemoteConnectionConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/RemoteConnectionConfiguration.cs
index df20dd4e..a9c87990 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/RemoteConnectionConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/RemoteConnectionConfiguration.cs
@@ -12,6 +12,13 @@ using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.MachineHive
{
+ ///
+ /// 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.
+ ///
[Serializable]
internal class RemoteConnectionConfiguration : MachineHiveConfiguration
{
@@ -23,5 +30,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public RemoteConnectionConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
{
}
+
+ public override bool Reset()
+ {
+ return DisableFeature();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/SwitchUserConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/SwitchUserConfiguration.cs
index 1a35010a..21aaa955 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/SwitchUserConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/MachineHive/SwitchUserConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public SwitchUserConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/RegistryConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/RegistryConfiguration.cs
index bb5f4d65..eaaf9ed6 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/RegistryConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/RegistryConfiguration.cs
@@ -30,6 +30,8 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations
itemsToRestore = new List();
}
+ protected abstract bool IsHiveAvailable(RegistryDataItem item);
+
public override bool DisableFeature()
{
var success = true;
@@ -66,7 +68,7 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations
}
else
{
- logger.Warn("Failed to enabled feature!");
+ logger.Warn("Failed to enable feature!");
}
return success;
@@ -148,7 +150,26 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations
return success;
}
- protected abstract bool IsHiveAvailable(RegistryDataItem item);
+ 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)
{
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChangePasswordConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChangePasswordConfiguration.cs
index 68ef2b67..02579004 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChangePasswordConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChangePasswordConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public ChangePasswordConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChromeNotificationConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChromeNotificationConfiguration.cs
index 35cee403..efb5e831 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChromeNotificationConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/ChromeNotificationConfiguration.cs
@@ -16,9 +16,9 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
/// 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
+ /// • 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.
///
[Serializable]
internal class ChromeNotificationConfiguration : UserHiveConfiguration
@@ -31,5 +31,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public ChromeNotificationConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/LockWorkstationConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/LockWorkstationConfiguration.cs
index d597294b..bf8b00d2 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/LockWorkstationConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/LockWorkstationConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public LockWorkstationConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/SignoutConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/SignoutConfiguration.cs
index ad027e19..10ae1afc 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/SignoutConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/SignoutConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public SignoutConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/TaskManagerConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/TaskManagerConfiguration.cs
index b1ca350f..5f6556dc 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/TaskManagerConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/TaskManagerConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public TaskManagerConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
{
}
+
+ public override bool Reset()
+ {
+ return DeleteConfiguration();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/VmwareOverlayConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/VmwareOverlayConfiguration.cs
index fd834736..b9d2946e 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/VmwareOverlayConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/RegistryConfigurations/UserHive/VmwareOverlayConfiguration.cs
@@ -24,5 +24,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.RegistryConfigurations.
public VmwareOverlayConfiguration(Guid groupId, ILogger logger, string sid, string userName) : base(groupId, logger, sid, userName)
{
}
+
+ public override bool Reset()
+ {
+ return EnableFeature();
+ }
}
}
diff --git a/SafeExamBrowser.Lockdown/FeatureConfigurations/ServiceConfigurations/WindowsUpdateConfiguration.cs b/SafeExamBrowser.Lockdown/FeatureConfigurations/ServiceConfigurations/WindowsUpdateConfiguration.cs
index b3eb2b5f..42ecb3a1 100644
--- a/SafeExamBrowser.Lockdown/FeatureConfigurations/ServiceConfigurations/WindowsUpdateConfiguration.cs
+++ b/SafeExamBrowser.Lockdown/FeatureConfigurations/ServiceConfigurations/WindowsUpdateConfiguration.cs
@@ -23,5 +23,10 @@ namespace SafeExamBrowser.Lockdown.FeatureConfigurations.ServiceConfigurations
public WindowsUpdateConfiguration(Guid groupId, ILogger logger) : base(groupId, logger)
{
}
+
+ public override bool Reset()
+ {
+ return EnableFeature();
+ }
}
}
diff --git a/SafeExamBrowser.ResetUtility/CompositionRoot.cs b/SafeExamBrowser.ResetUtility/CompositionRoot.cs
index 6dd88e43..bf1ae37d 100644
--- a/SafeExamBrowser.ResetUtility/CompositionRoot.cs
+++ b/SafeExamBrowser.ResetUtility/CompositionRoot.cs
@@ -14,11 +14,13 @@ using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Lockdown;
using SafeExamBrowser.Logging;
using SafeExamBrowser.ResetUtility.Procedure;
+using SafeExamBrowser.SystemComponents;
namespace SafeExamBrowser.ResetUtility
{
internal class CompositionRoot
{
+ private ProcedureContext context;
private ILogger logger;
internal ProcedureStep InitialStep { get; private set; }
@@ -26,14 +28,8 @@ namespace SafeExamBrowser.ResetUtility
internal void BuildObjectGraph()
{
- var context = new ProcedureContext();
-
InitializeLogging();
-
- context.CreateBackup = CreateBackup;
- context.Logger = logger;
- context.MainMenu = BuildMainMenu(context);
- context.Update = new SystemConfigurationUpdate(new ModuleLogger(logger, nameof(SystemConfigurationUpdate)));
+ InitializeContext();
InitialStep = new Initialization(context);
NativeMethods = new NativeMethods();
@@ -68,6 +64,17 @@ namespace SafeExamBrowser.ResetUtility
return new FeatureConfigurationBackup(filePath, new ModuleLogger(logger, nameof(FeatureConfigurationBackup)));
}
+ private void InitializeContext()
+ {
+ context = new ProcedureContext();
+ context.ConfigurationFactory = new FeatureConfigurationFactory(new ModuleLogger(logger, nameof(FeatureConfigurationFactory)));
+ context.CreateBackup = CreateBackup;
+ context.Logger = logger;
+ context.MainMenu = BuildMainMenu(context);
+ context.Update = new SystemConfigurationUpdate(new ModuleLogger(logger, nameof(SystemConfigurationUpdate)));
+ context.UserInfo = new UserInfo(new ModuleLogger(logger, nameof(UserInfo)));
+ }
+
private void InitializeLogging()
{
var appDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), nameof(SafeExamBrowser));
diff --git a/SafeExamBrowser.ResetUtility/Procedure/ProcedureContext.cs b/SafeExamBrowser.ResetUtility/Procedure/ProcedureContext.cs
index 4d8ba85d..ae19b45f 100644
--- a/SafeExamBrowser.ResetUtility/Procedure/ProcedureContext.cs
+++ b/SafeExamBrowser.ResetUtility/Procedure/ProcedureContext.cs
@@ -10,14 +10,17 @@ using System;
using System.Collections.Generic;
using SafeExamBrowser.Contracts.Lockdown;
using SafeExamBrowser.Contracts.Logging;
+using SafeExamBrowser.Contracts.SystemComponents;
namespace SafeExamBrowser.ResetUtility.Procedure
{
internal class ProcedureContext
{
+ internal IFeatureConfigurationFactory ConfigurationFactory { get; set; }
internal Func CreateBackup { get; set; }
internal ILogger Logger { get; set; }
internal IList MainMenu { get; set; }
internal ISystemConfigurationUpdate Update { get; set; }
+ internal IUserInfo UserInfo { get; set; }
}
}
diff --git a/SafeExamBrowser.ResetUtility/Procedure/ProcedureStep.cs b/SafeExamBrowser.ResetUtility/Procedure/ProcedureStep.cs
index 320af50f..30d4b51a 100644
--- a/SafeExamBrowser.ResetUtility/Procedure/ProcedureStep.cs
+++ b/SafeExamBrowser.ResetUtility/Procedure/ProcedureStep.cs
@@ -57,6 +57,25 @@ namespace SafeExamBrowser.ResetUtility.Procedure
Console.CursorVisible = false;
}
+ protected void ClearLine(int top)
+ {
+ Console.SetCursorPosition(0, top);
+ Console.WriteLine(new String(' ', Console.BufferWidth));
+ Console.SetCursorPosition(0, top);
+ }
+
+ protected string ReadLine()
+ {
+ Console.Write("> ");
+ Console.CursorVisible = true;
+
+ var input = Console.ReadLine();
+
+ Console.CursorVisible = false;
+
+ return input;
+ }
+
protected void ShowError(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
diff --git a/SafeExamBrowser.ResetUtility/Procedure/Reset.cs b/SafeExamBrowser.ResetUtility/Procedure/Reset.cs
index 3300b6f2..9a03ae22 100644
--- a/SafeExamBrowser.ResetUtility/Procedure/Reset.cs
+++ b/SafeExamBrowser.ResetUtility/Procedure/Reset.cs
@@ -6,6 +6,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SafeExamBrowser.Contracts.Lockdown;
+
namespace SafeExamBrowser.ResetUtility.Procedure
{
internal class Reset : ProcedureStep
@@ -16,6 +21,15 @@ namespace SafeExamBrowser.ResetUtility.Procedure
internal override ProcedureStepResult Execute()
{
+ InitializeConsole();
+
+ var success = TryGetUserInfo(out var userName, out var sid);
+
+ if (success)
+ {
+ ResetAll(userName, sid);
+ }
+
return ProcedureStepResult.Continue;
}
@@ -23,5 +37,120 @@ namespace SafeExamBrowser.ResetUtility.Procedure
{
return new MainMenu(Context);
}
+
+ private bool TryGetUserInfo(out string userName, out string sid)
+ {
+ Console.ForegroundColor = ConsoleColor.DarkYellow;
+ Console.WriteLine("IMPORTANT: Some configuration values are user specific. In order to reset these values, the user specified below needs to be logged in!");
+ Console.ForegroundColor = ForegroundColor;
+ Console.WriteLine();
+ Console.WriteLine("Please enter the name of the user for which to reset all configuration values:");
+
+ userName = ReadLine();
+
+ StartProgressAnimation();
+ var success = Context.UserInfo.TryGetSidForUser(userName, out sid);
+ StopProgressAnimation();
+
+ while (!success)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"Could not find user '{userName}'!");
+ Console.ForegroundColor = ForegroundColor;
+
+ var tryAgain = new MenuOption { IsSelected = true, Text = "Try again" };
+ var mainMenu = new MenuOption { Text = "Return to main menu" };
+
+ ShowMenu(new List { tryAgain, mainMenu });
+
+ if (mainMenu.IsSelected)
+ {
+ break;
+ }
+
+ ClearLine(Console.CursorTop - 1);
+ ClearLine(Console.CursorTop - 1);
+ ClearLine(Console.CursorTop - 1);
+ ClearLine(Console.CursorTop - 1);
+
+ userName = ReadLine();
+ success = Context.UserInfo.TryGetSidForUser(userName, out sid);
+ }
+
+ return success;
+ }
+
+ private void ResetAll(string userName, string sid)
+ {
+ var configurations = Context.ConfigurationFactory.CreateAll(Guid.NewGuid(), sid, userName);
+ var failed = new List();
+
+ Logger.Info($"Attempting to reset all configuration values for user '{userName}' with SID '{sid}'...");
+ Console.WriteLine();
+ Console.WriteLine("Initiating reset procedure...");
+
+ foreach (var configuration in configurations)
+ {
+ var success = configuration.Reset();
+
+ if (!success)
+ {
+ failed.Add(configuration);
+ }
+
+ ShowProgress(configurations.IndexOf(configuration) + 1, configurations.Count);
+ }
+
+ PerformUpdate();
+
+ if (failed.Any())
+ {
+ HandleFailure(failed);
+ }
+ else
+ {
+ HandleSuccess();
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("Press any key to return to the main menu.");
+ Console.ReadKey();
+ }
+
+ private void PerformUpdate()
+ {
+ Console.WriteLine();
+ Console.WriteLine("Performing system configuration update, please wait...");
+ StartProgressAnimation();
+ Context.Update.Execute();
+ StopProgressAnimation();
+ Console.WriteLine("Update completed.");
+ }
+
+ private void HandleFailure(IList configurations)
+ {
+ Logger.Warn($"Failed to reset {configurations.Count} items!");
+ Console.WriteLine();
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"Failed to reset {configurations.Count} items!");
+
+ foreach (var configuration in configurations)
+ {
+ Console.WriteLine($" - {configuration.GetType().Name}");
+ }
+
+ Console.ForegroundColor = ForegroundColor;
+ Console.WriteLine();
+ Console.WriteLine("Please consult the application log for more information.");
+ }
+
+ private void HandleSuccess()
+ {
+ Logger.Info("Successfully reset all changes!");
+ Console.WriteLine();
+ Console.ForegroundColor = ConsoleColor.DarkGreen;
+ Console.WriteLine("Successfully reset all changes!");
+ Console.ForegroundColor = ForegroundColor;
+ }
}
}
diff --git a/SafeExamBrowser.ResetUtility/Procedure/Restore.cs b/SafeExamBrowser.ResetUtility/Procedure/Restore.cs
index 4adabc01..b472dc93 100644
--- a/SafeExamBrowser.ResetUtility/Procedure/Restore.cs
+++ b/SafeExamBrowser.ResetUtility/Procedure/Restore.cs
@@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -104,13 +103,11 @@ namespace SafeExamBrowser.ResetUtility.Procedure
private void PerformUpdate()
{
- Logger.Info("Starting system configuration update...");
Console.WriteLine();
Console.WriteLine("Performing system configuration update, please wait...");
StartProgressAnimation();
Context.Update.Execute();
StopProgressAnimation();
- Logger.Info("Update completed.");
Console.WriteLine("Update completed.");
}
@@ -160,7 +157,7 @@ namespace SafeExamBrowser.ResetUtility.Procedure
next = new Reset(Context);
}
- Logger.Info($"The user chose {(yes.IsSelected ? "" : "not ")}to perform a reset for now.");
+ Logger.Info($"The user chose {(yes.IsSelected ? "" : "not ")}to perform a reset.");
}
}
}
diff --git a/SafeExamBrowser.ResetUtility/SafeExamBrowser.ResetUtility.csproj b/SafeExamBrowser.ResetUtility/SafeExamBrowser.ResetUtility.csproj
index b12c3df3..ba2c5f64 100644
--- a/SafeExamBrowser.ResetUtility/SafeExamBrowser.ResetUtility.csproj
+++ b/SafeExamBrowser.ResetUtility/SafeExamBrowser.ResetUtility.csproj
@@ -92,6 +92,10 @@
{e107026c-2011-4552-a7d8-3a0d37881df6}
SafeExamBrowser.Logging
+
+ {acee2ef1-14d2-4b52-8994-5c053055bb51}
+ SafeExamBrowser.SystemComponents
+
diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs
index c690932d..fb6f6c76 100644
--- a/SafeExamBrowser.Runtime/CompositionRoot.cs
+++ b/SafeExamBrowser.Runtime/CompositionRoot.cs
@@ -71,7 +71,7 @@ namespace SafeExamBrowser.Runtime
var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime);
var sessionContext = new SessionContext();
var uiFactory = new UserInterfaceFactory(text);
- var userInfo = new UserInfo();
+ var userInfo = new UserInfo(ModuleLogger(nameof(UserInfo)));
var bootstrapOperations = new Queue();
var sessionOperations = new Queue();
diff --git a/SafeExamBrowser.SystemComponents/UserInfo.cs b/SafeExamBrowser.SystemComponents/UserInfo.cs
index b16e80a3..2e5897ea 100644
--- a/SafeExamBrowser.SystemComponents/UserInfo.cs
+++ b/SafeExamBrowser.SystemComponents/UserInfo.cs
@@ -7,13 +7,25 @@
*/
using System;
+using System.Diagnostics;
using System.Security.Principal;
+using System.Text.RegularExpressions;
+using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.SystemComponents;
namespace SafeExamBrowser.SystemComponents
{
public class UserInfo : IUserInfo
{
+ private const string SID_REGEX_PATTERN = @"S-\d(-\d+)+";
+
+ private ILogger logger;
+
+ public UserInfo(ILogger logger)
+ {
+ this.logger = logger;
+ }
+
public string GetUserName()
{
return Environment.UserName;
@@ -23,5 +35,77 @@ namespace SafeExamBrowser.SystemComponents
{
return WindowsIdentity.GetCurrent().User.Value;
}
+
+ public bool TryGetSidForUser(string userName, out string sid)
+ {
+ var strategies = new Func[] { NtAccount, Wmi };
+ var success = false;
+
+ sid = default(string);
+
+ foreach (var strategy in strategies)
+ {
+ try
+ {
+ sid = strategy.Invoke(userName);
+
+ if (IsValid(sid))
+ {
+ logger.Info($"Found SID '{sid}' via '{strategy.Method.Name}' for user name '{userName}'!");
+ success = true;
+
+ break;
+ }
+
+ logger.Warn($"Retrieved invalid SID '{sid}' via '{strategy.Method.Name}' for user name '{userName}'!");
+ }
+ catch (Exception e)
+ {
+ logger.Error($"Failed to get SID via '{strategy.Method.Name}' for user name '{userName}'!", e);
+ }
+ }
+
+ if (!success)
+ {
+ logger.Error($"All attempts to retrieve SID for user name '{userName}' failed!");
+ }
+
+ return success;
+ }
+
+ private string NtAccount(string userName)
+ {
+ var account = new NTAccount(userName);
+
+ if (account.IsValidTargetType(typeof(SecurityIdentifier)))
+ {
+ return account.Translate(typeof(SecurityIdentifier)).Value;
+ }
+
+ return null;
+ }
+
+ private string Wmi(string userName)
+ {
+ var process = new Process();
+
+ process.StartInfo.FileName = "cmd.exe";
+ process.StartInfo.Arguments = string.Format("/c \"wmic useraccount where name='{0}' get sid\"", userName);
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.CreateNoWindow = true;
+ process.Start();
+ process.WaitForExit(5000);
+
+ var output = process.StandardOutput.ReadToEnd();
+ var match = Regex.Match(output, SID_REGEX_PATTERN);
+
+ return match.Success ? match.Value : null;
+ }
+
+ private bool IsValid(string sid)
+ {
+ return !String.IsNullOrWhiteSpace(sid) && Regex.IsMatch(sid, $"^{SID_REGEX_PATTERN}$");
+ }
}
}