diff --git a/SMBLibrary/NTFileStore/Adapter/NTFileSystemAdapter.cs b/SMBLibrary/NTFileStore/Adapter/NTFileSystemAdapter.cs index 6de7bb3..90c0bc2 100644 --- a/SMBLibrary/NTFileStore/Adapter/NTFileSystemAdapter.cs +++ b/SMBLibrary/NTFileStore/Adapter/NTFileSystemAdapter.cs @@ -370,6 +370,12 @@ namespace SMBLibrary return NTStatus.STATUS_SUCCESS; } + public NTStatus DeviceIOControl(object handle, uint ctlCode, byte[] input, out byte[] output, int maxOutputLength) + { + output = null; + return NTStatus.STATUS_NOT_SUPPORTED; + } + public void Log(Severity severity, string message) { // To be thread-safe we must capture the delegate reference first diff --git a/SMBLibrary/NTFileStore/Enums/IoControlCode.cs b/SMBLibrary/NTFileStore/Enums/IoControlCode.cs new file mode 100644 index 0000000..0360fb7 --- /dev/null +++ b/SMBLibrary/NTFileStore/Enums/IoControlCode.cs @@ -0,0 +1,22 @@ + +namespace SMBLibrary +{ + public enum IoControlCode : uint + { + FSCTL_DFS_GET_REFERRALS = 0x00060194, // SMB2-specific processing + FSCTL_DFS_GET_REFERRALS_EX = 0x000601B0, // SMB2-specific processing + FSCTL_SET_REPARSE_POINT = 0x000900A4, // SMB2-specific processing + FSCTL_FILE_LEVEL_TRIM = 0x00098208, // SMB2-specific processing + FSCTL_PIPE_WAIT = 0x00110018, // SMB2-specific processing + FSCTL_PIPE_PEEK = 0x0011400C, // SMB2-specific processing + FSCTL_PIPE_TRANSCEIVE = 0x0011C017, // SMB2-specific processing + FSCTL_SRV_REQUEST_RESUME_KEY = 0x00140078, // SMB2-specific processing + FSCTL_VALIDATE_NEGOTIATE_INFO = 0x00140204, // SMB2-specific processing + FSCTL_LMR_REQUEST_RESILIENCY = 0x001401D4, // SMB2-specific processing + FSCTL_QUERY_NETWORK_INTERFACE_INFO = 0x001401FC, // SMB2-specific processing + FSCTL_SRV_ENUMERATE_SNAPSHOTS = 0x00144064, // SMB2-specific processing + FSCTL_SRV_COPYCHUNK = 0x001440F2, // SMB2-specific processing + FSCTL_SRV_READ_HASH = 0x001441BB, // SMB2-specific processing + FSCTL_SRV_COPYCHUNK_WRITE = 0x001480F2, // SMB2-specific processing + } +} diff --git a/SMBLibrary/NTFileStore/INTFileStore.cs b/SMBLibrary/NTFileStore/INTFileStore.cs index d47f584..9f4b3a1 100644 --- a/SMBLibrary/NTFileStore/INTFileStore.cs +++ b/SMBLibrary/NTFileStore/INTFileStore.cs @@ -33,5 +33,7 @@ namespace SMBLibrary NTStatus SetFileInformation(object handle, FileInformation information); NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass); + + NTStatus DeviceIOControl(object handle, uint ctlCode, byte[] input, out byte[] output, int maxOutputLength); } } diff --git a/SMBLibrary/NTFileStore/NamedPipeStore.cs b/SMBLibrary/NTFileStore/NamedPipeStore.cs index da9f7f2..d0922c1 100644 --- a/SMBLibrary/NTFileStore/NamedPipeStore.cs +++ b/SMBLibrary/NTFileStore/NamedPipeStore.cs @@ -99,6 +99,28 @@ namespace SMBLibrary return NTStatus.STATUS_SUCCESS; } + public NTStatus DeviceIOControl(object handle, uint ctlCode, byte[] input, out byte[] output, int maxOutputLength) + { + output = null; + if (ctlCode == (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE) + { + int numberOfBytesWritten; + NTStatus writeStatus = WriteFile(out numberOfBytesWritten, handle, 0, input); + if (writeStatus != NTStatus.STATUS_SUCCESS) + { + return writeStatus; + } + NTStatus readStatus = ReadFile(out output, handle, 0, maxOutputLength); + if (readStatus != NTStatus.STATUS_SUCCESS) + { + return readStatus; + } + return NTStatus.STATUS_SUCCESS; + } + + return NTStatus.STATUS_NOT_SUPPORTED; + } + public NTStatus QueryDirectory(out List result, object directoryHandle, string fileName, FileInformationClass informationClass) { result = null; diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj index 62e0d1e..d6ba0d1 100644 --- a/SMBLibrary/SMBLibrary.csproj +++ b/SMBLibrary/SMBLibrary.csproj @@ -93,6 +93,7 @@ + diff --git a/SMBLibrary/Server/SMB1/NTTransactHelper.cs b/SMBLibrary/Server/SMB1/NTTransactHelper.cs index 903ff00..1d5a644 100644 --- a/SMBLibrary/Server/SMB1/NTTransactHelper.cs +++ b/SMBLibrary/Server/SMB1/NTTransactHelper.cs @@ -80,7 +80,7 @@ namespace SMBLibrary.Server.SMB1 } else if (subcommand is NTTransactIOCTLRequest) { - subcommandResponse = GetSubcommandResponse(header, (NTTransactIOCTLRequest)subcommand); + subcommandResponse = GetSubcommandResponse(header, (NTTransactIOCTLRequest)subcommand, share, state); } else if (subcommand is NTTransactSetSecurityDescriptor) { @@ -112,25 +112,28 @@ namespace SMBLibrary.Server.SMB1 return response; } - private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, NTTransactIOCTLRequest subcommand) + private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state) { - const uint FSCTL_CREATE_OR_GET_OBJECT_ID = 0x900C0; - + SMB1Session session = state.GetSession(header.UID); NTTransactIOCTLResponse response = new NTTransactIOCTLResponse(); if (subcommand.IsFsctl) { - if (subcommand.FunctionCode == FSCTL_CREATE_OR_GET_OBJECT_ID) + OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); + if (openFile == null) { - ObjectIDBufferType1 objectID = new ObjectIDBufferType1(); - objectID.ObjectId = Guid.NewGuid(); - response.Data = objectID.GetBytes(); - return response; - } - else - { - header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; + header.Status = NTStatus.STATUS_INVALID_HANDLE; return null; } + int maxOutputLength = UInt16.MaxValue; + byte[] output; + header.Status = share.FileStore.DeviceIOControl(openFile.Handle, subcommand.FunctionCode, subcommand.Data, out output, maxOutputLength); + if (header.Status != NTStatus.STATUS_SUCCESS) + { + return null; + } + + response.Data = output; + return response; } else { diff --git a/SMBLibrary/Server/SMB1/TransactionHelper.cs b/SMBLibrary/Server/SMB1/TransactionHelper.cs index 333c953..2fcb4af 100644 --- a/SMBLibrary/Server/SMB1/TransactionHelper.cs +++ b/SMBLibrary/Server/SMB1/TransactionHelper.cs @@ -134,14 +134,7 @@ namespace SMBLibrary.Server.SMB1 } else if (subcommand is TransactionTransactNamedPipeRequest) { - if (!(share is NamedPipeShare)) - { - // [MS-CIFS] If the pipe is not a message mode pipe, the Trans subsystem MUST fail the request with STATUS_INVALID_PARAMETER - header.Status = NTStatus.STATUS_INVALID_PARAMETER; - return new ErrorResponse(CommandName.SMB_COM_TRANSACTION); - } - - subcommandResponse = TransactionSubcommandHelper.GetSubcommandResponse(header, (TransactionTransactNamedPipeRequest)subcommand, (NamedPipeShare)share, state); + subcommandResponse = TransactionSubcommandHelper.GetSubcommandResponse(header, (TransactionTransactNamedPipeRequest)subcommand, share, state); } else if (subcommand is TransactionRawWriteNamedPipeRequest) { diff --git a/SMBLibrary/Server/SMB1/TransactionSubcommandHelper.cs b/SMBLibrary/Server/SMB1/TransactionSubcommandHelper.cs index fecd1f1..ea4c8df 100644 --- a/SMBLibrary/Server/SMB1/TransactionSubcommandHelper.cs +++ b/SMBLibrary/Server/SMB1/TransactionSubcommandHelper.cs @@ -16,7 +16,7 @@ namespace SMBLibrary.Server.SMB1 { public class TransactionSubcommandHelper { - internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, TransactionTransactNamedPipeRequest subcommand, NamedPipeShare share, SMB1ConnectionState state) + internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, TransactionTransactNamedPipeRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); @@ -26,19 +26,15 @@ namespace SMBLibrary.Server.SMB1 return null; } + int maxOutputLength = UInt16.MaxValue; + 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) + { + return null; + } TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse(); - int numberOfBytesWritten; - header.Status = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, 0, subcommand.WriteData); - if (header.Status != NTStatus.STATUS_SUCCESS) - { - return null; - } - int maxCount = UInt16.MaxValue; - header.Status = share.FileStore.ReadFile(out response.ReadData, openFile.Handle, 0, maxCount); - if (header.Status != NTStatus.STATUS_SUCCESS) - { - return null; - } + response.ReadData = output; return response; } } diff --git a/SMBLibrary/Server/SMB2/IOCtlHelper.cs b/SMBLibrary/Server/SMB2/IOCtlHelper.cs index d0f448e..7d1691b 100644 --- a/SMBLibrary/Server/SMB2/IOCtlHelper.cs +++ b/SMBLibrary/Server/SMB2/IOCtlHelper.cs @@ -14,14 +14,11 @@ namespace SMBLibrary.Server.SMB2 { public class IOCtlHelper { - private const uint FSCTL_DFS_GET_REFERRALS = 0x00060194; - private const uint FSCTL_DFS_GET_REFERRALS_EX = 0x000601B0; - private const uint FSCTL_PIPE_TRANSCEIVE = 0x0011C017; - internal static SMB2Command GetIOCtlResponse(IOCtlRequest request, ISMBShare share, SMB2ConnectionState state) { SMB2Session session = state.GetSession(request.Header.SessionID); - if (request.CtlCode == FSCTL_DFS_GET_REFERRALS || request.CtlCode == FSCTL_DFS_GET_REFERRALS_EX) + if (request.CtlCode == (uint)IoControlCode.FSCTL_DFS_GET_REFERRALS || + request.CtlCode == (uint)IoControlCode.FSCTL_DFS_GET_REFERRALS_EX) { // [MS-SMB2] 3.3.5.15.2 Handling a DFS Referral Information Request return new ErrorResponse(request.CommandName, NTStatus.STATUS_FS_DRIVER_REQUIRED); @@ -33,29 +30,18 @@ namespace SMBLibrary.Server.SMB2 return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); } - if (share is NamedPipeShare) + int maxOutputLength = (int)request.MaxOutputResponse; + byte[] output; + NTStatus status = share.FileStore.DeviceIOControl(openFile.Handle, request.CtlCode, request.Input, out output, maxOutputLength); + if (status != NTStatus.STATUS_SUCCESS) { - if (request.CtlCode == FSCTL_PIPE_TRANSCEIVE) - { - IOCtlResponse response = new IOCtlResponse(); - response.CtlCode = request.CtlCode; - int numberOfBytesWritten; - NTStatus writeStatus = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, 0, request.Input); - if (writeStatus != NTStatus.STATUS_SUCCESS) - { - return new ErrorResponse(request.CommandName, writeStatus); - } - int maxCount = (int)request.MaxOutputResponse; - NTStatus readStatus = share.FileStore.ReadFile(out response.Output, openFile.Handle, 0, maxCount); - if (readStatus != NTStatus.STATUS_SUCCESS) - { - return new ErrorResponse(request.CommandName, readStatus); - } - return response; - } + return new ErrorResponse(request.CommandName, status); } - return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED); + IOCtlResponse response = new IOCtlResponse(); + response.CtlCode = request.CtlCode; + response.Output = output; + return response; } } }