Harden NTFS SMB login retry
This commit is contained in:
@@ -17,6 +17,9 @@ namespace LiamNtfs
|
||||
{
|
||||
public class cNtfsBase
|
||||
{
|
||||
private const int ErrorSessionCredentialConflict = 1219;
|
||||
private const int ErrorNotConnected = 2250;
|
||||
|
||||
private cNtfsLogonInfo privLogonInfo = null;
|
||||
private int scanningDepth;
|
||||
public PrincipalContext adContext = null;
|
||||
@@ -58,15 +61,40 @@ namespace LiamNtfs
|
||||
LogonInfo.UserSecret,
|
||||
LogonInfo.User,
|
||||
0);
|
||||
if(result == 1219)
|
||||
|
||||
if (result == ErrorSessionCredentialConflict)
|
||||
{
|
||||
result = WNetCancelConnection2(LogonInfo.TargetNetworkName,0,true);
|
||||
if (result == 0)
|
||||
return await privLogonAsync(LogonInfo);
|
||||
var originalResult = result;
|
||||
var cancelResult = WNetCancelConnection2(LogonInfo.TargetNetworkName, 0, true);
|
||||
|
||||
if (cancelResult == 0 || cancelResult == ErrorNotConnected)
|
||||
{
|
||||
result = WNetAddConnection2(
|
||||
netResource,
|
||||
LogonInfo.UserSecret,
|
||||
LogonInfo.User,
|
||||
0);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
cLogManager.LogEntry(
|
||||
$"NTFS login retry succeeded after SMB conflict on '{LogonInfo.TargetNetworkName}'. Initial add returned {originalResult} ({BuildWin32Message(originalResult)}), cancel returned {cancelResult} ({BuildWin32Message(cancelResult)}).",
|
||||
LogLevels.Debug);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CreateNtfsLoginException(LogonInfo, originalResult, cancelResult, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CreateNtfsLoginException(LogonInfo, originalResult, cancelResult, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
throw new Win32Exception(result);
|
||||
throw CreateNtfsLoginException(LogonInfo, result, null, null);
|
||||
}
|
||||
var FSLogon = true;
|
||||
|
||||
@@ -83,6 +111,39 @@ namespace LiamNtfs
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Exception CreateNtfsLoginException(cNtfsLogonInfo logonInfo, int addResult, int? cancelResult, int? retryResult)
|
||||
{
|
||||
var stages = new List<string>
|
||||
{
|
||||
$"WNetAddConnection2={addResult} ({BuildWin32Message(addResult)})"
|
||||
};
|
||||
|
||||
if (cancelResult.HasValue)
|
||||
stages.Add($"WNetCancelConnection2('{logonInfo?.TargetNetworkName}')={cancelResult.Value} ({BuildWin32Message(cancelResult.Value)})");
|
||||
|
||||
if (retryResult.HasValue)
|
||||
stages.Add($"RetryAdd={retryResult.Value} ({BuildWin32Message(retryResult.Value)})");
|
||||
|
||||
var details = string.Join(", ", stages);
|
||||
var message = $"NTFS login to '{logonInfo?.TargetNetworkName}' for user '{logonInfo?.User}' failed. {details}.";
|
||||
|
||||
if (addResult == ErrorSessionCredentialConflict)
|
||||
{
|
||||
message += " This usually indicates an existing SMB/DFS session to the same server with a different credential context.";
|
||||
|
||||
if (cancelResult == ErrorNotConnected)
|
||||
message += " The exact DFS/share path was not registered as a disconnectable connection, so the conflicting session is likely held under a different remote name or DFS target.";
|
||||
}
|
||||
|
||||
var nativeResult = retryResult ?? cancelResult ?? addResult;
|
||||
return new InvalidOperationException(message, new Win32Exception(nativeResult));
|
||||
}
|
||||
|
||||
private static string BuildWin32Message(int errorCode)
|
||||
{
|
||||
return new Win32Exception(errorCode).Message;
|
||||
}
|
||||
|
||||
private async Task<bool> privRelogon()
|
||||
{
|
||||
if (privLogonInfo == null)
|
||||
|
||||
Reference in New Issue
Block a user