SEBWIN-312: Started implementing application whitelist mechanism.

This commit is contained in:
dbuechel 2019-10-30 15:49:35 +01:00
parent f778d5b848
commit 2b976e8150
6 changed files with 158 additions and 132 deletions

View file

@ -97,7 +97,7 @@ namespace SafeExamBrowser.Client.Operations
private void FinalizeApplications()
{
// TODO: Terminate all running applications!
}
private OperationResult HandleAutoTerminationFailure(IList<RunningApplication> applications)

View file

@ -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<BlacklistApplication> blacklist;
private Guid? captureHookId;
private Guid? foregroundHookId;
@ -31,6 +31,7 @@ namespace SafeExamBrowser.Monitoring.Applications
private IProcessFactory processFactory;
private Timer timer;
private IList<WhitelistApplication> 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;

View file

@ -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})";
}
}
}

View file

@ -55,6 +55,7 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Applications\Window.cs" />
<Compile Include="Display\Bounds.cs" />
<Compile Include="Display\DisplayMonitor.cs" />
<Compile Include="Keyboard\KeyboardInterceptor.cs" />

View file

@ -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");

View file

@ -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