Add NTFS ensure level filters

This commit is contained in:
Meik
2026-07-09 22:43:41 +02:00
parent e23397c2ac
commit 3ca1a41816
2 changed files with 198 additions and 3 deletions

View File

@@ -53,6 +53,20 @@ namespace C4IT.LIAM
public int Level { get; set; } = -1;
}
private sealed class cNtfsLevelRange
{
public bool IsConfigured { get; set; }
public bool IsValid { get; set; } = true;
public int MinLevel { get; set; } = int.MinValue;
public int MaxLevel { get; set; } = int.MaxValue;
public string ErrorMessage { get; set; } = string.Empty;
public bool Contains(int level)
{
return !IsConfigured || level >= MinLevel && level <= MaxLevel;
}
}
private sealed class cNtfsDataAreaDiagnostics
{
private const int MaxSamples = 10;
@@ -123,6 +137,10 @@ namespace C4IT.LIAM
private const string AdditionalConfigurationExcludePathsKey = "NtfsExcludePaths";
private const string AdditionalConfigurationIncludePathsKey = "NtfsIncludePaths";
private const string AdditionalConfigurationTraverseBoundaryPathKey = "NtfsTraverseBoundaryPath";
private const string AdditionalConfigurationPermissionGroupsMinLevelKey = "NtfsPermissionGroupsMinLevel";
private const string AdditionalConfigurationPermissionGroupsMaxLevelKey = "NtfsPermissionGroupsMaxLevel";
private const string AdditionalConfigurationTraverseGroupsMinLevelKey = "NtfsTraverseGroupsMinLevel";
private const string AdditionalConfigurationTraverseGroupsMaxLevelKey = "NtfsTraverseGroupsMaxLevel";
private const string AdditionalConfigurationGroupNameSanitizeReplacementKey = "NtfsGroupNameSanitizeReplacement";
private const string AdditionalConfigurationPreserveAdGroupNameCaseKey = "PreserveNtfsAdGroupNameCase";
private const string AdditionalConfigurationAdDomainControllersKey = "NtfsAdDomainControllers";
@@ -1155,6 +1173,16 @@ namespace C4IT.LIAM
});
}
string levelSkipReason;
if (!IsPermissionLevelManagedPath(classification, out levelSkipReason))
{
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
{
resultErrorId = 30008,
resultMessage = levelSkipReason
});
}
var parentPath = Directory.GetParent(folderPath)?.FullName;
var engine = CreateFilesystemEngine(
folderPath,
@@ -1208,7 +1236,19 @@ namespace C4IT.LIAM
});
}
if (!IsTraversePermissionManagedPath(folderPath))
var traverseLevelRange = GetTraverseLevelRange();
if (!traverseLevelRange.IsValid)
{
var message = $"NTFS traverse ensure skipped for '{folderPath}' because {traverseLevelRange.ErrorMessage}";
LogEntry(message, LogLevels.Warning);
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
{
resultErrorId = 30008,
resultMessage = message
});
}
if (!IsTraversePermissionCandidatePath(folderPath))
{
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
{
@@ -1355,6 +1395,16 @@ namespace C4IT.LIAM
}
private bool IsPermissionManagedPath(string path, params eNtfsPathKind[] supportedKinds)
{
if (!IsPermissionManagedPathCandidate(path, supportedKinds))
return false;
var classification = ClassifyPath(path);
string levelSkipReason;
return IsPermissionLevelManagedPath(classification, out levelSkipReason);
}
private bool IsPermissionManagedPathCandidate(string path, params eNtfsPathKind[] supportedKinds)
{
var classification = ClassifyPath(path);
if (!IsSupportedPermissionManagedPathKind(classification, supportedKinds))
@@ -1365,13 +1415,25 @@ namespace C4IT.LIAM
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
return false;
return IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule);
if (!IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule))
return false;
return true;
}
private bool IsTraversePermissionManagedPath(string path)
{
if (!IsTraversePermissionCandidatePath(path))
return false;
string levelSkipReason;
return IsTraverseLevelManagedPath(ClassifyPath(path), out levelSkipReason);
}
private bool IsTraversePermissionCandidatePath(string path)
{
if (string.IsNullOrWhiteSpace(GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey)))
return IsPermissionManagedFolderPath(path);
return IsPermissionManagedPathCandidate(path, eNtfsPathKind.Folder);
var classification = ClassifyPath(path);
if (classification == null || classification.Kind == eNtfsPathKind.ServerRoot || classification.Kind == eNtfsPathKind.Unknown)
@@ -1385,6 +1447,112 @@ namespace C4IT.LIAM
return Directory.Exists(path);
}
private bool IsPermissionLevelManagedPath(cNtfsPathClassification classification, out string skipReason)
{
return IsLevelManagedPath(
classification,
GetPermissionLevelRange(),
"permission group ensure",
out skipReason);
}
private bool IsTraverseLevelManagedPath(cNtfsPathClassification classification, out string skipReason)
{
return IsLevelManagedPath(
classification,
GetTraverseLevelRange(),
"traverse group ensure",
out skipReason);
}
private bool IsLevelManagedPath(cNtfsPathClassification classification, cNtfsLevelRange range, string operationName, out string skipReason)
{
skipReason = string.Empty;
if (classification == null)
{
skipReason = $"NTFS {operationName} skipped because the path could not be classified.";
return false;
}
if (range == null || !range.IsConfigured)
return true;
if (!range.IsValid)
{
skipReason = $"NTFS {operationName} skipped for '{classification.NormalizedPath}' because {range.ErrorMessage}";
LogEntry(skipReason, LogLevels.Warning);
return false;
}
if (range.Contains(classification.Level))
return true;
skipReason = $"NTFS {operationName} skipped for '{classification.NormalizedPath}' because level {classification.Level} is outside configured range {range.MinLevel}..{range.MaxLevel}.";
LogEntry(skipReason, LogLevels.Debug);
return false;
}
private cNtfsLevelRange GetPermissionLevelRange()
{
return GetConfiguredLevelRange(
AdditionalConfigurationPermissionGroupsMinLevelKey,
AdditionalConfigurationPermissionGroupsMaxLevelKey,
"permission group level range");
}
private cNtfsLevelRange GetTraverseLevelRange()
{
return GetConfiguredLevelRange(
AdditionalConfigurationTraverseGroupsMinLevelKey,
AdditionalConfigurationTraverseGroupsMaxLevelKey,
"traverse group level range");
}
private cNtfsLevelRange GetConfiguredLevelRange(string minKey, string maxKey, string label)
{
var range = new cNtfsLevelRange();
var minValue = GetAdditionalConfigurationValue(minKey);
var maxValue = GetAdditionalConfigurationValue(maxKey);
var hasMin = !string.IsNullOrWhiteSpace(minValue);
var hasMax = !string.IsNullOrWhiteSpace(maxValue);
range.IsConfigured = hasMin || hasMax;
if (!range.IsConfigured)
return range;
int parsedValue;
if (hasMin)
{
if (!int.TryParse(minValue, out parsedValue))
{
range.IsValid = false;
range.ErrorMessage = $"AdditionalConfiguration '{minKey}' for {label} is not a valid integer: '{minValue}'.";
return range;
}
range.MinLevel = parsedValue;
}
if (hasMax)
{
if (!int.TryParse(maxValue, out parsedValue))
{
range.IsValid = false;
range.ErrorMessage = $"AdditionalConfiguration '{maxKey}' for {label} is not a valid integer: '{maxValue}'.";
return range;
}
range.MaxLevel = parsedValue;
}
if (range.MinLevel > range.MaxLevel)
{
range.IsValid = false;
range.ErrorMessage = $"AdditionalConfiguration {label} is invalid because min level {range.MinLevel} is greater than max level {range.MaxLevel}.";
}
return range;
}
private static bool IsSupportedPermissionManagedPathKind(cNtfsPathClassification classification, params eNtfsPathKind[] supportedKinds)
{
if (classification == null || supportedKinds == null || supportedKinds.Length == 0)