Bladeren bron

SMB1: Bugfix: The server was returning more bytes than the specified maximum for SMB_COM_NT_TRANSACT and SMB_COM_NT_TRANSACT commands

Tal Aloni 7 jaren geleden
bovenliggende
commit
9669f16bb5

+ 1 - 1
SMBLibrary/Server/ConnectionState/ProcessStateObject.cs

@@ -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;
     }
 }

+ 8 - 26
SMBLibrary/Server/ConnectionState/SMB1ConnectionState.cs

@@ -189,22 +189,14 @@ namespace SMBLibrary.Server
             return false;
         }
 
-        public ProcessStateObject GetProcessState(uint processID)
+        public ProcessStateObject CreateProcessState(uint processID)
         {
-            if (m_processStateList.ContainsKey(processID))
-            {
-                return m_processStateList[processID];
-            }
-            else
-            {
-                return null;
-            }
+            ProcessStateObject processState = new ProcessStateObject();
+            m_processStateList[processID] = processState;
+            return processState;
         }
 
-        /// <summary>
-        /// Get or Create process state
-        /// </summary>
-        public ProcessStateObject ObtainProcessState(uint processID)
+        public ProcessStateObject GetProcessState(uint processID)
         {
             if (m_processStateList.ContainsKey(processID))
             {
@@ -212,23 +204,13 @@ namespace SMBLibrary.Server
             }
             else
             {
-                ProcessStateObject processState = new ProcessStateObject();
-                m_processStateList[processID] = processState;
-                return processState;
+                return null;
             }
         }
 
-        public uint? GetMaxDataCount(uint processID)
+        public void RemoveProcessState(uint processID)
         {
-            ProcessStateObject processState = GetProcessState(processID);
-            if (processState != null)
-            {
-                return processState.MaxDataCount;
-            }
-            else
-            {
-                return null;
-            }
+            m_processStateList.Remove(processID);
         }
     }
 }

+ 9 - 7
SMBLibrary/Server/SMB1/NTTransactHelper.cs

@@ -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)

+ 4 - 4
SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs

@@ -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;

+ 12 - 12
SMBLibrary/Server/SMB1/TransactionHelper.cs

@@ -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)
             {

+ 2 - 2
SMBLibrary/Server/SMB1/TransactionSubcommandHelper.cs

@@ -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)