Harden NTFS SMB login retry

This commit is contained in:
Meik
2026-03-18 13:48:24 +01:00
parent 8573698e33
commit 2bda1010d1

View File

@@ -17,6 +17,9 @@ namespace LiamNtfs
{ {
public class cNtfsBase public class cNtfsBase
{ {
private const int ErrorSessionCredentialConflict = 1219;
private const int ErrorNotConnected = 2250;
private cNtfsLogonInfo privLogonInfo = null; private cNtfsLogonInfo privLogonInfo = null;
private int scanningDepth; private int scanningDepth;
public PrincipalContext adContext = null; public PrincipalContext adContext = null;
@@ -58,15 +61,40 @@ namespace LiamNtfs
LogonInfo.UserSecret, LogonInfo.UserSecret,
LogonInfo.User, LogonInfo.User,
0); 0);
if(result == 1219)
if (result == ErrorSessionCredentialConflict)
{ {
result = WNetCancelConnection2(LogonInfo.TargetNetworkName,0,true); 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) if (result == 0)
return await privLogonAsync(LogonInfo); {
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) if (result != 0)
{ {
throw new Win32Exception(result); throw CreateNtfsLoginException(LogonInfo, result, null, null);
} }
var FSLogon = true; var FSLogon = true;
@@ -83,6 +111,39 @@ namespace LiamNtfs
return false; 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() private async Task<bool> privRelogon()
{ {
if (privLogonInfo == null) if (privLogonInfo == null)