SMBServer: SMB2: Improved handling of compunded related requests

This commit is contained in:
Tal Aloni 2017-09-03 20:06:48 +03:00
parent 73b27366c5
commit df58913372

View file

@ -19,20 +19,51 @@ namespace SMBLibrary.Server
{
List<SMB2Command> responseChain = new List<SMB2Command>();
FileID? fileID = null;
NTStatus? fileIDStatus = null;
foreach (SMB2Command request in requestChain)
{
if (request.Header.IsRelatedOperations && fileID.HasValue)
SMB2Command response;
if (request.Header.IsRelatedOperations && RequestContainsFileID(request))
{
SetRequestFileID(request, fileID.Value);
if (fileIDStatus != null && fileIDStatus != NTStatus.STATUS_SUCCESS && fileIDStatus != NTStatus.STATUS_BUFFER_OVERFLOW)
{
// [MS-SMB2] When the current request requires a FileId and the previous request either contains
// or generates a FileId, if the previous request fails with an error, the server SHOULD fail the
// current request with the same error code returned by the previous request.
state.LogToServer(Severity.Verbose, "Compunded related request {0} failed because FileId generation failed.", request.CommandName);
response = new ErrorResponse(request.CommandName, fileIDStatus.Value);
}
else if (fileID.HasValue)
{
SetRequestFileID(request, fileID.Value);
response = ProcessSMB2Command(request, ref state);
}
else
{
// [MS-SMB2] When the current request requires a FileId, and if the previous request neither contains
// nor generates a FileId, the server MUST fail the compounded request with STATUS_INVALID_PARAMETER.
state.LogToServer(Severity.Verbose, "Compunded related request {0} failed, the previous request neither contains nor generates a FileId.", request.CommandName);
response = new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
}
}
SMB2Command response = ProcessSMB2Command(request, ref state);
else
{
fileID = GetRequestFileID(request);
response = ProcessSMB2Command(request, ref state);
}
if (response != null)
{
UpdateSMB2Header(response, request, state);
responseChain.Add(response);
if (!request.Header.IsRelatedOperations)
if (GeneratesFileID(response))
{
fileID = GetResponseFileID(response);
fileIDStatus = response.Header.Status;
}
else if (RequestContainsFileID(request))
{
fileIDStatus = response.Header.Status;
}
}
}
@ -250,6 +281,65 @@ namespace SMBLibrary.Server
response.Header.IsSigned = (request.Header.IsSigned || signingRequired) && !isInterimResponse;
}
private static bool RequestContainsFileID(SMB2Command command)
{
return (command is ChangeNotifyRequest ||
command is CloseRequest ||
command is FlushRequest ||
command is IOCtlRequest ||
command is LockRequest ||
command is QueryDirectoryRequest ||
command is QueryInfoRequest ||
command is ReadRequest ||
command is SetInfoRequest ||
command is WriteRequest);
}
private static FileID? GetRequestFileID(SMB2Command command)
{
if (command is ChangeNotifyRequest)
{
return ((ChangeNotifyRequest)command).FileId;
}
else if (command is CloseRequest)
{
return ((CloseRequest)command).FileId;
}
else if (command is FlushRequest)
{
return ((FlushRequest)command).FileId;
}
else if (command is IOCtlRequest)
{
return ((IOCtlRequest)command).FileId;
}
else if (command is LockRequest)
{
return ((LockRequest)command).FileId;
}
else if (command is QueryDirectoryRequest)
{
return ((QueryDirectoryRequest)command).FileId;
}
else if (command is QueryInfoRequest)
{
return ((QueryInfoRequest)command).FileId;
}
else if (command is ReadRequest)
{
return ((ReadRequest)command).FileId;
}
else if (command is SetInfoRequest)
{
return ((SetInfoRequest)command).FileId;
}
else if (command is WriteRequest)
{
return ((WriteRequest)command).FileId;
}
return null;
}
private static void SetRequestFileID(SMB2Command command, FileID fileID)
{
if (command is ChangeNotifyRequest)
@ -294,6 +384,12 @@ namespace SMBLibrary.Server
}
}
private static bool GeneratesFileID(SMB2Command command)
{
return (command.CommandName == SMB2CommandName.Create ||
command.CommandName == SMB2CommandName.IOCtl);
}
private static FileID? GetResponseFileID(SMB2Command command)
{
if (command is CreateResponse)