From 2b976e8150e0cbfb85ef2105653b698eaf337309 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Wed, 30 Oct 2019 15:49:35 +0100 Subject: [PATCH] SEBWIN-312: Started implementing application whitelist mechanism. --- .../Operations/ApplicationOperation.cs | 2 +- .../Applications/ApplicationMonitor.cs | 192 ++++++++++++------ .../Applications/Window.cs | 23 +++ .../SafeExamBrowser.Monitoring.csproj | 1 + SebWindowsConfig/SEBSettings.cs | 66 +----- SebWindowsConfig/SebWindowsConfigForm.cs | 6 +- 6 files changed, 158 insertions(+), 132 deletions(-) create mode 100644 SafeExamBrowser.Monitoring/Applications/Window.cs diff --git a/SafeExamBrowser.Client/Operations/ApplicationOperation.cs b/SafeExamBrowser.Client/Operations/ApplicationOperation.cs index eba09ab2..fdec9ff9 100644 --- a/SafeExamBrowser.Client/Operations/ApplicationOperation.cs +++ b/SafeExamBrowser.Client/Operations/ApplicationOperation.cs @@ -97,7 +97,7 @@ namespace SafeExamBrowser.Client.Operations private void FinalizeApplications() { - + // TODO: Terminate all running applications! } private OperationResult HandleAutoTerminationFailure(IList applications) diff --git a/SafeExamBrowser.Monitoring/Applications/ApplicationMonitor.cs b/SafeExamBrowser.Monitoring/Applications/ApplicationMonitor.cs index efe07c5b..adf2eec5 100644 --- a/SafeExamBrowser.Monitoring/Applications/ApplicationMonitor.cs +++ b/SafeExamBrowser.Monitoring/Applications/ApplicationMonitor.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Timers; @@ -21,7 +22,6 @@ namespace SafeExamBrowser.Monitoring.Applications { public class ApplicationMonitor : IApplicationMonitor { - private IntPtr activeWindow; private IList blacklist; private Guid? captureHookId; private Guid? foregroundHookId; @@ -31,6 +31,7 @@ namespace SafeExamBrowser.Monitoring.Applications private IProcessFactory processFactory; private Timer timer; private IList whitelist; + private Window activeWindow; public event ExplorerStartedEventHandler ExplorerStarted; public event TerminationFailedEventHandler TerminationFailed; @@ -50,42 +51,9 @@ namespace SafeExamBrowser.Monitoring.Applications { var result = new InitializationResult(); - foreach (var application in settings.Blacklist) - { - blacklist.Add(application); - } - - foreach (var application in settings.Whitelist) - { - whitelist.Add(application); - } - - logger.Debug($"Initialized blacklist with {blacklist.Count} applications{(blacklist.Any() ? $": {string.Join(", ", blacklist.Select(a => a.ExecutableName))}" : ".")}"); - logger.Debug($"Initialized whitelist with {whitelist.Count} applications{(whitelist.Any() ? $": {string.Join(", ", whitelist.Select(a => a.ExecutableName))}" : ".")}"); - - processes = processFactory.GetAllRunning(); - - foreach (var process in processes) - { - foreach (var application in blacklist) - { - var isBlacklisted = BelongsToApplication(process, application); - - if (isBlacklisted && !application.AutoTerminate) - { - AddForTermination(application.ExecutableName, process, result); - } - else if (isBlacklisted && application.AutoTerminate && !TryTerminate(process)) - { - AddFailed(application.ExecutableName, process, result); - } - } - - foreach (var application in whitelist) - { - // TODO: Check if application is running, auto-terminate or add to result. - } - } + InitializeProcesses(); + InitializeBlacklist(settings, result); + InitializeWhitelist(settings, result); return result; } @@ -135,10 +103,13 @@ namespace SafeExamBrowser.Monitoring.Applications return success; } - private void SystemEvent_WindowChanged(IntPtr window) + private void SystemEvent_WindowChanged(IntPtr handle) { - if (window != IntPtr.Zero && activeWindow != window) + if (handle != IntPtr.Zero && activeWindow?.Handle != handle) { + var title = nativeMethods.GetWindowTitle(handle); + var window = new Window { Handle = handle, Title = title }; + logger.Debug($"Window has changed from {activeWindow} to {window}."); activeWindow = window; @@ -239,12 +210,28 @@ namespace SafeExamBrowser.Monitoring.Applications return sameName || sameOriginalName; } - private void Close(IntPtr window) + private bool BelongsToApplication(IProcess process, WhitelistApplication application) { - var title = nativeMethods.GetWindowTitle(window); + // TODO: Window title and renderer process handling! + // TODO: WRONG! With original name, both must match! + var sameName = process.Name.Equals(Path.GetFileNameWithoutExtension(application.ExecutableName), StringComparison.OrdinalIgnoreCase); + var sameOriginalName = process.OriginalName?.Equals(application.OriginalName, StringComparison.OrdinalIgnoreCase) == true; - nativeMethods.SendCloseMessageTo(window); - logger.Info($"Sent close message to window '{title}' with handle = {window}."); + return sameName || sameOriginalName; + } + + private bool BelongsToSafeExamBrowser(IProcess process) + { + var isRuntime = process.Name == "SafeExamBrowser" && process.OriginalName == "SafeExamBrowser"; + var isClient = process.Name == "SafeExamBrowser.Client" && process.OriginalName == "SafeExamBrowser.Client"; + + return isRuntime || isClient; + } + + private void Close(Window window) + { + nativeMethods.SendCloseMessageTo(window.Handle); + logger.Info($"Sent close message to window {window}."); } private void HandleExplorerStart(IProcess process) @@ -253,25 +240,74 @@ namespace SafeExamBrowser.Monitoring.Applications Task.Run(() => ExplorerStarted?.Invoke()); } - private bool IsAllowed(IntPtr window) + private void InitializeProcesses() { - var processId = nativeMethods.GetProcessIdFor(window); - // TODO: Allow only if in whitelist! - //var process = processFactory.GetById(Convert.ToInt32(processId)); + processes = processFactory.GetAllRunning(); + logger.Debug($"Initialized {processes.Count} currently running processes."); + } - //if (process != null) - //{ - // var allowed = process.Name == "SafeExamBrowser" || process.Name == "SafeExamBrowser.Client"; + private void InitializeBlacklist(ApplicationSettings settings, InitializationResult result) + { + foreach (var application in settings.Blacklist) + { + blacklist.Add(application); + } - // if (!allowed) - // { - // logger.Warn($"Window with handle = {window} belongs to not allowed process '{process.Name}'!"); - // } + logger.Debug($"Initialized blacklist with {blacklist.Count} applications{(blacklist.Any() ? $": {string.Join(", ", blacklist.Select(a => a.ExecutableName))}" : ".")}"); - // return allowed; - //} + foreach (var process in processes) + { + foreach (var application in blacklist) + { + var isBlacklisted = BelongsToApplication(process, application); - return true; + if (isBlacklisted) + { + if (!application.AutoTerminate) + { + AddForTermination(application.ExecutableName, process, result); + } + else if (application.AutoTerminate && !TryTerminate(process)) + { + AddFailed(application.ExecutableName, process, result); + } + + break; + } + } + } + } + + private void InitializeWhitelist(ApplicationSettings settings, InitializationResult result) + { + foreach (var application in settings.Whitelist) + { + whitelist.Add(application); + } + + logger.Debug($"Initialized whitelist with {whitelist.Count} applications{(whitelist.Any() ? $": {string.Join(", ", whitelist.Select(a => a.ExecutableName))}" : ".")}"); + + foreach (var process in processes) + { + foreach (var application in whitelist) + { + var isWhitelisted = BelongsToApplication(process, application); + + if (isWhitelisted) + { + if (!application.AllowRunning && !application.AutoTerminate) + { + AddForTermination(application.ExecutableName, process, result); + } + else if (!application.AllowRunning && application.AutoTerminate && !TryTerminate(process)) + { + AddFailed(application.ExecutableName, process, result); + } + + break; + } + } + } } private bool IsAllowed(IProcess process) @@ -289,18 +325,46 @@ namespace SafeExamBrowser.Monitoring.Applications return true; } - private bool TryHide(IntPtr window) + private bool IsAllowed(Window window) { - var title = nativeMethods.GetWindowTitle(window); - var success = nativeMethods.HideWindow(window); - - if (success) + var processId = Convert.ToInt32(nativeMethods.GetProcessIdFor(window.Handle)); + + if (processFactory.TryGetById(processId, out var process)) { - logger.Info($"Hid window '{title}' with handle = {window}."); + if (BelongsToSafeExamBrowser(process)) + { + return true; + } + + foreach (var application in whitelist) + { + if (BelongsToApplication(process, application)) + { + return true; + } + } + + logger.Warn($"Window {window} belongs to not allowed process '{process.Name}'!"); } else { - logger.Warn($"Failed to hide window '{title}' with handle = {window}!"); + logger.Error($"Could not find process for window {window} and process with ID = {processId}!"); + } + + return false; + } + + private bool TryHide(Window window) + { + var success = nativeMethods.HideWindow(window.Handle); + + if (success) + { + logger.Info($"Successfully hid window {window}."); + } + else + { + logger.Warn($"Failed to hide window {window}!"); } return success; diff --git a/SafeExamBrowser.Monitoring/Applications/Window.cs b/SafeExamBrowser.Monitoring/Applications/Window.cs new file mode 100644 index 00000000..e0d075ee --- /dev/null +++ b/SafeExamBrowser.Monitoring/Applications/Window.cs @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System; + +namespace SafeExamBrowser.Monitoring.Applications +{ + internal class Window + { + public IntPtr Handle { get; set; } + public string Title { get; set; } + + public override string ToString() + { + return $"'{Title}' ({Handle})"; + } + } +} diff --git a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj index d24a251b..591798c7 100644 --- a/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj +++ b/SafeExamBrowser.Monitoring/SafeExamBrowser.Monitoring.csproj @@ -55,6 +55,7 @@ + diff --git a/SebWindowsConfig/SEBSettings.cs b/SebWindowsConfig/SEBSettings.cs index bf54e4c9..a1081e36 100644 --- a/SebWindowsConfig/SEBSettings.cs +++ b/SebWindowsConfig/SEBSettings.cs @@ -440,7 +440,6 @@ namespace SebWindowsConfig public static ListObj permittedProcessList = new ListObj(); public static DictObj permittedProcessData = new DictObj(); public static DictObj permittedProcessDataDefault = new DictObj(); - public static DictObj permittedProcessDataXulRunner = new DictObj(); public static int permittedArgumentIndex; public static ListObj permittedArgumentList = new ListObj(); @@ -510,7 +509,6 @@ namespace SebWindowsConfig SEBSettings.permittedProcessList = new ListObj(); SEBSettings.permittedProcessData = new DictObj(); SEBSettings.permittedProcessDataDefault = new DictObj(); - SEBSettings.permittedProcessDataXulRunner = new DictObj(); SEBSettings.permittedArgumentList = new ListObj(); SEBSettings.permittedArgumentData = new DictObj(); @@ -720,24 +718,6 @@ namespace SebWindowsConfig //SEBSettings.permittedArgumentListXulRunner.Add(SEBSettings.permittedArgumentDataXulRunner1); //SEBSettings.permittedArgumentListXulRunner.Add(SEBSettings.permittedArgumentDataXulRunner2); - // Create a Firefox process with the SEB argument list - SEBSettings.permittedProcessDataXulRunner.Clear(); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyActive , true); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyAutostart , true); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyIconInTaskbar , true); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyRunInBackground , false); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyAllowUser , false); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyStrongKill , false); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyOS , IntWin); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyTitle , "SEB"); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyDescription, ""); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyExecutable, SEBClientInfo.XUL_RUNNER); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyOriginalName, SEBClientInfo.XUL_RUNNER); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyPath , "../xulrunner/"); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyIdentifier , "Firefox"); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyWindowHandlingProcess , ""); - SEBSettings.permittedProcessDataXulRunner.Add(SEBSettings.KeyArguments , new ListObj()); - // Default settings for permitted process data SEBSettings.permittedProcessDataDefault.Clear(); SEBSettings.permittedProcessDataDefault.Add(SEBSettings.KeyActive , true); @@ -1470,48 +1450,6 @@ namespace SebWindowsConfig return ret; } - // ********************************************** - // Add XulRunnerProcess to Permitted Process List - // ********************************************** - public static void PermitXulRunnerProcess() - { - // Get the Permitted Process List - SEBSettings.permittedProcessList = (ListObj)SEBSettings.settingsCurrent[SEBSettings.KeyPermittedProcesses]; - - // Position of XulRunner process in Permitted Process List - int indexOfProcessXulRunnerExe = -1; - - // Traverse Permitted Processes of currently opened file - for (int listIndex = 0; listIndex < SEBSettings.permittedProcessList.Count; listIndex++) - { - SEBSettings.permittedProcessData = (DictObj)SEBSettings.permittedProcessList[listIndex]; - - // Check if XulRunner process is in Permitted Process List - if (SEBSettings.permittedProcessData[SEBSettings.KeyExecutable].Equals(SEBClientInfo.XUL_RUNNER)) - { - indexOfProcessXulRunnerExe = listIndex; - break; - } - else if (SEBSettings.permittedProcessData[SEBSettings.KeyExecutable].Equals("xulrunner.exe")) - { - //Backwards Compatibility: Use Firefox instead of Xulrunner as SEB Browser - ((DictObj)SEBSettings.permittedProcessList[listIndex])[SEBSettings.KeyExecutable] = SEBClientInfo.XUL_RUNNER; - ((DictObj)SEBSettings.permittedProcessList[listIndex])[SEBSettings.KeyOriginalName] = SEBClientInfo.XUL_RUNNER; - ((DictObj)SEBSettings.permittedProcessList[listIndex])[SEBSettings.KeyIdentifier] = "Firefox"; - indexOfProcessXulRunnerExe = listIndex; - break; - } - } - - // If XulRunner process was not in Permitted Process List, insert it at the beginning - if (indexOfProcessXulRunnerExe == -1) - { - SEBSettings.permittedProcessList.Insert(0, SEBSettings.permittedProcessDataXulRunner); - } - - AddDefaultProhibitedProcesses(); - } - public static void AddDefaultProhibitedProcesses() { // Get the Prohibited Process list @@ -1773,7 +1711,7 @@ namespace SebWindowsConfig SEBSettings.FillSettingsArrays(); // Add the XulRunner process to the Permitted Process List, if necessary - SEBSettings.PermitXulRunnerProcess(); + SEBSettings.AddDefaultProhibitedProcesses(); } @@ -1818,7 +1756,7 @@ namespace SebWindowsConfig // Add the XulRunner process to the Permitted Process List, if necessary //SEBSettings.LoggSettingsDictionary(ref SEBSettings.settingsDefault, "DebugSettingsDefaultInReadSebConfigurationFilePermitBefore.txt"); //SEBSettings.LoggSettingsDictionary(ref SEBSettings.settingsCurrent, "DebugSettingsCurrentInReadSebConfigurationFilePermitBefore.txt"); - SEBSettings.PermitXulRunnerProcess(); + SEBSettings.AddDefaultProhibitedProcesses(); //SEBSettings.LoggSettingsDictionary(ref SEBSettings.settingsDefault, "DebugSettingsDefaultInReadSebConfigurationFilePermitAfter.txt"); //SEBSettings.LoggSettingsDictionary(ref SEBSettings.settingsCurrent, "DebugSettingsCurrentInReadSebConfigurationFilePermitAfter.txt"); diff --git a/SebWindowsConfig/SebWindowsConfigForm.cs b/SebWindowsConfig/SebWindowsConfigForm.cs index 605475e6..9c8db0f3 100644 --- a/SebWindowsConfig/SebWindowsConfigForm.cs +++ b/SebWindowsConfig/SebWindowsConfigForm.cs @@ -95,7 +95,7 @@ namespace SebWindowsConfig // Set all the default values for the Plist structure "SEBSettings.settingsCurrent" SEBSettings.RestoreDefaultAndCurrentSettings(); - SEBSettings.PermitXulRunnerProcess(); + SEBSettings.AddDefaultProhibitedProcesses(); // Initialise the global variables for the GUI widgets InitialiseGlobalVariablesForGUIWidgets(); @@ -1385,7 +1385,7 @@ namespace SebWindowsConfig settingsPassword = ""; settingsPasswordFieldsContainHash = false; SEBSettings.RestoreDefaultAndCurrentSettings(); - SEBSettings.PermitXulRunnerProcess(); + SEBSettings.AddDefaultProhibitedProcesses(); // Check if currently edited settings are local client settings (in %appdata% or %commonappdata%) or the default settings (no client settings saved yet) if (!currentPathSebConfigFile.Equals(SEBClientInfo.SebClientSettingsAppDataFile) && !currentPathSebConfigFile.Equals(SEBClientInfo.SebClientSettingsProgramDataFile) && !currentPathSebConfigFile.Equals(SEBUIStrings.settingsTitleDefaultSettings)) @@ -1435,7 +1435,7 @@ namespace SebWindowsConfig settingsPassword = ""; settingsPasswordFieldsContainHash = false; SEBSettings.RestoreDefaultAndCurrentSettings(); - SEBSettings.PermitXulRunnerProcess(); + SEBSettings.AddDefaultProhibitedProcesses(); currentPathSebConfigFile = SEBUIStrings.settingsTitleDefaultSettings; // Update URL filter rules, also the seb-Browser white/blacklist keys, // which are necessary for compatibility to SEB 2.1.x