mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-07-25 02:18:16 +02:00
SMB1: Bugfix: The server was returning more bytes than the specified maximum for SMB_COM_NT_TRANSACT and SMB_COM_NT_TRANSACT commands
This commit is contained in:
parent
fb06e4df46
commit
9669f16bb5
6 changed files with 37 additions and 53 deletions
|
@ -13,12 +13,12 @@ namespace SMBLibrary.Server
|
|||
internal class ProcessStateObject
|
||||
{
|
||||
public ushort SubcommandID;
|
||||
public uint MaxDataCount; // The maximum number of TransactionData bytes that the client accepts in the transaction response
|
||||
public string Name; // The pathname of the [..] named pipe to which the transaction subcommand applies, or a client-supplied [..] name for the transaction.
|
||||
public byte[] TransactionSetup;
|
||||
public byte[] TransactionParameters;
|
||||
public byte[] TransactionData;
|
||||
public int TransactionParametersReceived; // length in bytes
|
||||
public int TransactionDataReceived; // length in bytes
|
||||
public uint MaxDataCount;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,6 +189,13 @@ namespace SMBLibrary.Server
|
|||
return false;
|
||||
}
|
||||
|
||||
public ProcessStateObject CreateProcessState(uint processID)
|
||||
{
|
||||
ProcessStateObject processState = new ProcessStateObject();
|
||||
m_processStateList[processID] = processState;
|
||||
return processState;
|
||||
}
|
||||
|
||||
public ProcessStateObject GetProcessState(uint processID)
|
||||
{
|
||||
if (m_processStateList.ContainsKey(processID))
|
||||
|
@ -201,34 +208,9 @@ namespace SMBLibrary.Server
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or Create process state
|
||||
/// </summary>
|
||||
public ProcessStateObject ObtainProcessState(uint processID)
|
||||
public void RemoveProcessState(uint processID)
|
||||
{
|
||||
if (m_processStateList.ContainsKey(processID))
|
||||
{
|
||||
return m_processStateList[processID];
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessStateObject processState = new ProcessStateObject();
|
||||
m_processStateList[processID] = processState;
|
||||
return processState;
|
||||
}
|
||||
}
|
||||
|
||||
public uint? GetMaxDataCount(uint processID)
|
||||
{
|
||||
ProcessStateObject processState = GetProcessState(processID);
|
||||
if (processState != null)
|
||||
{
|
||||
return processState.MaxDataCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
m_processStateList.Remove(processID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,10 @@ namespace SMBLibrary.Server.SMB1
|
|||
if (request.TransParameters.Length < request.TotalParameterCount ||
|
||||
request.TransData.Length < request.TotalDataCount)
|
||||
{
|
||||
ProcessStateObject processState = state.ObtainProcessState(header.PID);
|
||||
// A secondary transaction request is pending
|
||||
ProcessStateObject processState = state.CreateProcessState(header.PID);
|
||||
processState.SubcommandID = (ushort)request.Function;
|
||||
processState.MaxDataCount = request.MaxDataCount;
|
||||
processState.TransactionSetup = request.Setup;
|
||||
processState.TransactionParameters = new byte[request.TotalParameterCount];
|
||||
processState.TransactionData = new byte[request.TotalDataCount];
|
||||
|
@ -37,7 +38,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
else
|
||||
{
|
||||
// We have a complete command
|
||||
return GetCompleteNTTransactResponse(header, request.Function, request.Setup, request.TransParameters, request.TransData, share, state);
|
||||
return GetCompleteNTTransactResponse(header, request.MaxDataCount, request.Function, request.Setup, request.TransParameters, request.TransData, share, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,11 +66,12 @@ namespace SMBLibrary.Server.SMB1
|
|||
else
|
||||
{
|
||||
// We have a complete command
|
||||
return GetCompleteNTTransactResponse(header, (NTTransactSubcommandName)processState.SubcommandID, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state);
|
||||
state.RemoveProcessState(header.PID);
|
||||
return GetCompleteNTTransactResponse(header, processState.MaxDataCount, (NTTransactSubcommandName)processState.SubcommandID, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state);
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<SMB1Command> GetCompleteNTTransactResponse(SMB1Header header, NTTransactSubcommandName subcommandName, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
|
||||
internal static List<SMB1Command> GetCompleteNTTransactResponse(SMB1Header header, uint maxDataCount, NTTransactSubcommandName subcommandName, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
NTTransactSubcommand subcommand = NTTransactSubcommand.GetSubcommandRequest(subcommandName, requestSetup, requestParameters, requestData, header.UnicodeFlag);
|
||||
NTTransactSubcommand subcommandResponse = null;
|
||||
|
@ -80,7 +82,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
else if (subcommand is NTTransactIOCTLRequest)
|
||||
{
|
||||
subcommandResponse = GetSubcommandResponse(header, (NTTransactIOCTLRequest)subcommand, share, state);
|
||||
subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactIOCTLRequest)subcommand, share, state);
|
||||
}
|
||||
else if (subcommand is NTTransactSetSecurityDescriptor)
|
||||
{
|
||||
|
@ -112,7 +114,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
return GetNTTransactResponse(responseSetup, responseParameters, responseData, state.MaxBufferSize);
|
||||
}
|
||||
|
||||
private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
NTTransactIOCTLResponse response = new NTTransactIOCTLResponse();
|
||||
|
@ -124,7 +126,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||
return null;
|
||||
}
|
||||
int maxOutputLength = UInt16.MaxValue;
|
||||
int maxOutputLength = (int)maxDataCount;
|
||||
byte[] output;
|
||||
header.Status = share.FileStore.DeviceIOControl(openFile.Handle, subcommand.FunctionCode, subcommand.Data, out output, maxOutputLength);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
internal class Transaction2SubcommandHelper
|
||||
{
|
||||
internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, Transaction2FindFirst2Request subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, uint maxDataCount, Transaction2FindFirst2Request subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
string fileNamePattern = subcommand.FileName;
|
||||
|
@ -56,7 +56,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
|
||||
int entriesToReturn = Math.Min(subcommand.SearchCount, entries.Count);
|
||||
List<QueryDirectoryFileInformation> segment = entries.GetRange(0, entriesToReturn);
|
||||
int maxLength = (int)state.GetMaxDataCount(header.PID).Value;
|
||||
int maxLength = (int)maxDataCount;
|
||||
FindInformationList findInformationList;
|
||||
try
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
return response;
|
||||
}
|
||||
|
||||
internal static Transaction2FindNext2Response GetSubcommandResponse(SMB1Header header, Transaction2FindNext2Request subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
internal static Transaction2FindNext2Response GetSubcommandResponse(SMB1Header header, uint maxDataCount, Transaction2FindNext2Request subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
OpenSearch openSearch = session.GetOpenSearch(subcommand.SID);
|
||||
|
@ -103,7 +103,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
|
||||
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
|
||||
int maxLength = (int)state.GetMaxDataCount(header.PID).Value;
|
||||
int maxLength = (int)maxDataCount;
|
||||
int maxCount = Math.Min(openSearch.Entries.Count - openSearch.EnumerationLocation, subcommand.SearchCount);
|
||||
List<QueryDirectoryFileInformation> segment = openSearch.Entries.GetRange(openSearch.EnumerationLocation, maxCount);
|
||||
FindInformationList findInformationList;
|
||||
|
|
|
@ -22,13 +22,12 @@ namespace SMBLibrary.Server.SMB1
|
|||
/// </summary>
|
||||
internal static List<SMB1Command> GetTransactionResponse(SMB1Header header, TransactionRequest request, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
ProcessStateObject processState = state.ObtainProcessState(header.PID);
|
||||
processState.MaxDataCount = request.MaxDataCount;
|
||||
|
||||
if (request.TransParameters.Length < request.TotalParameterCount ||
|
||||
request.TransData.Length < request.TotalDataCount)
|
||||
{
|
||||
// A secondary transaction request is pending
|
||||
ProcessStateObject processState = state.CreateProcessState(header.PID);
|
||||
processState.MaxDataCount = request.MaxDataCount;
|
||||
processState.Name = request.Name;
|
||||
processState.TransactionSetup = request.Setup;
|
||||
processState.TransactionParameters = new byte[request.TotalParameterCount];
|
||||
|
@ -51,11 +50,11 @@ namespace SMBLibrary.Server.SMB1
|
|||
// We have a complete command
|
||||
if (request is Transaction2Request)
|
||||
{
|
||||
return GetCompleteTransaction2Response(header, request.Setup, request.TransParameters, request.TransData, share, state);
|
||||
return GetCompleteTransaction2Response(header, request.MaxDataCount, request.Setup, request.TransParameters, request.TransData, share, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetCompleteTransactionResponse(header, request.Name, request.Setup, request.TransParameters, request.TransData, share, state);
|
||||
return GetCompleteTransactionResponse(header, request.MaxDataCount, request.Name, request.Setup, request.TransParameters, request.TransData, share, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,18 +84,19 @@ namespace SMBLibrary.Server.SMB1
|
|||
else
|
||||
{
|
||||
// We have a complete command
|
||||
state.RemoveProcessState(header.PID);
|
||||
if (request is Transaction2SecondaryRequest)
|
||||
{
|
||||
return GetCompleteTransaction2Response(header, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state);
|
||||
return GetCompleteTransaction2Response(header, processState.MaxDataCount, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetCompleteTransactionResponse(header, processState.Name, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state);
|
||||
return GetCompleteTransactionResponse(header, processState.MaxDataCount, processState.Name, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<SMB1Command> GetCompleteTransactionResponse(SMB1Header header, string name, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
|
||||
internal static List<SMB1Command> GetCompleteTransactionResponse(SMB1Header header, uint maxDataCount, string name, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
if (String.Equals(name, @"\pipe\lanman", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
|
@ -140,7 +140,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
else if (subcommand is TransactionTransactNamedPipeRequest)
|
||||
{
|
||||
subcommandResponse = TransactionSubcommandHelper.GetSubcommandResponse(header, (TransactionTransactNamedPipeRequest)subcommand, share, state);
|
||||
subcommandResponse = TransactionSubcommandHelper.GetSubcommandResponse(header, maxDataCount, (TransactionTransactNamedPipeRequest)subcommand, share, state);
|
||||
}
|
||||
else if (subcommand is TransactionRawWriteNamedPipeRequest)
|
||||
{
|
||||
|
@ -178,7 +178,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
return GetTransactionResponse(false, responseSetup, responseParameters, responseData, state.MaxBufferSize);
|
||||
}
|
||||
|
||||
internal static List<SMB1Command> GetCompleteTransaction2Response(SMB1Header header, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
|
||||
internal static List<SMB1Command> GetCompleteTransaction2Response(SMB1Header header, uint maxDataCount, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
Transaction2Subcommand subcommand;
|
||||
try
|
||||
|
@ -194,11 +194,11 @@ namespace SMBLibrary.Server.SMB1
|
|||
|
||||
if (subcommand is Transaction2FindFirst2Request)
|
||||
{
|
||||
subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindFirst2Request)subcommand, share, state);
|
||||
subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, maxDataCount, (Transaction2FindFirst2Request)subcommand, share, state);
|
||||
}
|
||||
else if (subcommand is Transaction2FindNext2Request)
|
||||
{
|
||||
subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindNext2Request)subcommand, share, state);
|
||||
subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, maxDataCount, (Transaction2FindNext2Request)subcommand, share, state);
|
||||
}
|
||||
else if (subcommand is Transaction2QueryFSInformationRequest)
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
internal class TransactionSubcommandHelper
|
||||
{
|
||||
internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, TransactionTransactNamedPipeRequest subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, TransactionTransactNamedPipeRequest subcommand, ISMBShare share, SMB1ConnectionState state)
|
||||
{
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
|
||||
|
@ -26,7 +26,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
return null;
|
||||
}
|
||||
|
||||
int maxOutputLength = UInt16.MaxValue;
|
||||
int maxOutputLength = (int)maxDataCount;
|
||||
byte[] output;
|
||||
header.Status = share.FileStore.DeviceIOControl(openFile.Handle, (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE, subcommand.WriteData, out output, maxOutputLength);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue