Harden NTFS SMB login retry
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user