Pin NTFS AD operations to domain controller
This commit is contained in:
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -24,6 +25,7 @@ namespace LiamNtfs
|
||||
private cNtfsLogonInfo privLogonInfo = null;
|
||||
public PrincipalContext adContext = null;
|
||||
public DirectoryEntry directoryEntry = null;
|
||||
public string EffectiveDomainController { get; private set; } = null;
|
||||
public Exception LastException { get; private set; } = null;
|
||||
public string LastErrorMessage { get; private set; } = null;
|
||||
|
||||
@@ -49,8 +51,12 @@ namespace LiamNtfs
|
||||
//TODO: remove dummy delay?
|
||||
await Task.Delay(0);
|
||||
ResetError();
|
||||
adContext = new PrincipalContext(ContextType.Domain, LogonInfo.Domain, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
|
||||
var ldapPath = $"LDAP://{LogonInfo.Domain}/{LogonInfo.TargetGroupPath}";
|
||||
var adServer = ResolveEffectiveDomainController(LogonInfo);
|
||||
adContext = new PrincipalContext(ContextType.Domain, adServer, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
|
||||
EffectiveDomainController = adContext.ConnectedServer ?? adServer;
|
||||
LogEntry($"NTFS AD domain controller pinned to '{EffectiveDomainController}' for domain '{LogonInfo.Domain}'.", LogLevels.Debug);
|
||||
|
||||
var ldapPath = $"LDAP://{EffectiveDomainController}/{LogonInfo.TargetGroupPath}";
|
||||
directoryEntry = new DirectoryEntry
|
||||
{
|
||||
Path = ldapPath,
|
||||
@@ -69,6 +75,70 @@ namespace LiamNtfs
|
||||
return false;
|
||||
}
|
||||
|
||||
private string ResolveEffectiveDomainController(cNtfsLogonInfo logonInfo)
|
||||
{
|
||||
var configuredDomainControllers = ParseDomainControllers(logonInfo?.DomainControllers);
|
||||
foreach (var domainController in configuredDomainControllers)
|
||||
{
|
||||
if (CanConnectToDomainController(domainController, logonInfo))
|
||||
return domainController;
|
||||
|
||||
LogEntry($"Configured NTFS AD domain controller '{domainController}' is not reachable. Trying next candidate.", LogLevels.Warning);
|
||||
}
|
||||
|
||||
var pdc = TryGetPdcRoleOwner(logonInfo);
|
||||
if (!string.IsNullOrWhiteSpace(pdc))
|
||||
return pdc;
|
||||
|
||||
LogEntry($"Could not determine PDC emulator for domain '{logonInfo?.Domain}'. Falling back to domain locator.", LogLevels.Warning);
|
||||
return logonInfo?.Domain;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> ParseDomainControllers(string domainControllers)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(domainControllers))
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
return domainControllers
|
||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(i => i.Trim())
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i));
|
||||
}
|
||||
|
||||
private bool CanConnectToDomainController(string domainController, cNtfsLogonInfo logonInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var context = new PrincipalContext(ContextType.Domain, domainController, logonInfo.User, new NetworkCredential("", logonInfo.UserSecret).Password))
|
||||
return !string.IsNullOrWhiteSpace(context.ConnectedServer);
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E, LogLevels.Debug);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private string TryGetPdcRoleOwner(cNtfsLogonInfo logonInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
var credentials = new DirectoryContext(
|
||||
DirectoryContextType.Domain,
|
||||
logonInfo.Domain,
|
||||
logonInfo.User,
|
||||
new NetworkCredential("", logonInfo.UserSecret).Password);
|
||||
|
||||
using (var domain = Domain.GetDomain(credentials))
|
||||
return domain?.PdcRoleOwner?.Name;
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
LogException(E, LogLevels.Debug);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> privRelogon()
|
||||
{
|
||||
if (privLogonInfo == null)
|
||||
|
||||
Reference in New Issue
Block a user