From 347084020b93963df3f40332a50a17f1e185fbdc Mon Sep 17 00:00:00 2001 From: Tal Aloni Date: Thu, 31 Aug 2017 22:09:05 +0300 Subject: [PATCH] SMBServer: SMB1: Added support for SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO and SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO --- .../Enums/FindInformationLevel.cs | 8 +- .../FindFileIDBothDirectoryInfo.cs | 116 ++++++++++++++++++ .../FindFileIDFullDirectoryInfo.cs | 101 +++++++++++++++ SMBLibrary/SMBLibrary.csproj | 2 + .../SMB1FileStoreHelper.QueryDirectory.cs | 40 ++++++ .../SMB1/Transaction2SubcommandHelper.cs | 10 +- 6 files changed, 268 insertions(+), 9 deletions(-) create mode 100644 SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDBothDirectoryInfo.cs create mode 100644 SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDFullDirectoryInfo.cs diff --git a/SMBLibrary/SMB1FileStore/Enums/FindInformationLevel.cs b/SMBLibrary/SMB1FileStore/Enums/FindInformationLevel.cs index d7df7ac..943c6ce 100644 --- a/SMBLibrary/SMB1FileStore/Enums/FindInformationLevel.cs +++ b/SMBLibrary/SMB1FileStore/Enums/FindInformationLevel.cs @@ -3,12 +3,14 @@ namespace SMBLibrary.SMB1 { public enum FindInformationLevel : ushort { - SMB_INFO_STANDARD = 0x0001, // LANMAN2.0 - SMB_INFO_QUERY_EA_SIZE = 0x0002, // LANMAN2.0 - SMB_INFO_QUERY_EAS_FROM_LIST = 0x0003, // LANMAN2.0 + SMB_INFO_STANDARD = 0x0001, // LANMAN2.0 + SMB_INFO_QUERY_EA_SIZE = 0x0002, // LANMAN2.0 + SMB_INFO_QUERY_EAS_FROM_LIST = 0x0003, // LANMAN2.0 SMB_FIND_FILE_DIRECTORY_INFO = 0x0101, SMB_FIND_FILE_FULL_DIRECTORY_INFO = 0x0102, SMB_FIND_FILE_NAMES_INFO = 0x0103, SMB_FIND_FILE_BOTH_DIRECTORY_INFO = 0x0104, + SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO = 0x0105, // MS-SMB + SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO = 0x0106, // MS-SMB } } diff --git a/SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDBothDirectoryInfo.cs b/SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDBothDirectoryInfo.cs new file mode 100644 index 0000000..717de41 --- /dev/null +++ b/SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDBothDirectoryInfo.cs @@ -0,0 +1,116 @@ +/* Copyright (C) 2014-2017 Tal Aloni . All rights reserved. + * + * You can redistribute this program and/or modify it under the terms of + * the GNU Lesser Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using System.Text; +using Utilities; + +namespace SMBLibrary.SMB1 +{ + /// + /// SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO + /// + public class FindFileIDBothDirectoryInfo : FindInformation + { + public const int FixedLength = 104; + + public uint NextEntryOffset; + public uint FileIndex; // SHOULD be set to zero when sent in a response and SHOULD be ignored when received by the client + public DateTime? CreationTime; + public DateTime? LastAccessTime; + public DateTime? LastWriteTime; + public DateTime? LastChangeTime; + public long EndOfFile; + public long AllocationSize; + public ExtendedFileAttributes ExtFileAttributes; + //uint FileNameLength; // In bytes, MUST exclude the null termination. + public uint EASize; + //byte ShortNameLength; // In bytes + public byte Reserved; + public string ShortName; // 24 bytes, 8.3 name of the file in Unicode format + public ushort Reserved2; + public ulong FileID; + public string FileName; // OEM / Unicode character array. MUST be written as SMB_STRING, and read as fixed length string. + // Omitting the NULL termination from the FileName field in a single SMB_FIND_FILE_BOTH_DIRECTORY_INFO structure + // (as a response to TRANS2_QUERY_PATH_INFORMATION on a single directory) + // Will, in some rare but repeatable cases, cause issues with Windows XP SP3 as a client + // (the client will display an error message that the folder "refers to a location that is unavailable"...) + + public FindFileIDBothDirectoryInfo() : base(false) + { + } + + public FindFileIDBothDirectoryInfo(byte[] buffer, ref int offset, bool isUnicode) : base(false) + { + NextEntryOffset = LittleEndianReader.ReadUInt32(buffer, ref offset); + FileIndex = LittleEndianReader.ReadUInt32(buffer, ref offset); + CreationTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + LastAccessTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + LastWriteTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + LastChangeTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + EndOfFile = LittleEndianReader.ReadInt64(buffer, ref offset); + AllocationSize = LittleEndianReader.ReadInt64(buffer, ref offset); + ExtFileAttributes = (ExtendedFileAttributes)LittleEndianReader.ReadUInt32(buffer, ref offset); + uint fileNameLength = LittleEndianReader.ReadUInt32(buffer, ref offset); + EASize = LittleEndianReader.ReadUInt32(buffer, ref offset); + byte shortNameLength = ByteReader.ReadByte(buffer, ref offset); + Reserved = ByteReader.ReadByte(buffer, ref offset); + ShortName = ByteReader.ReadUTF16String(buffer, ref offset, 12); + ShortName = ShortName.Substring(0, shortNameLength); + Reserved2 = LittleEndianReader.ReadUInt16(buffer, ref offset); + FileID = LittleEndianReader.ReadUInt64(buffer, ref offset); + FileName = SMB1Helper.ReadFixedLengthString(buffer, ref offset, isUnicode, (int)fileNameLength); + } + + public override void WriteBytes(byte[] buffer, ref int offset, bool isUnicode) + { + uint fileNameLength = (uint)(isUnicode ? FileName.Length * 2 : FileName.Length); + byte shortNameLength = (byte)(ShortName.Length * 2); + + LittleEndianWriter.WriteUInt32(buffer, ref offset, NextEntryOffset); + LittleEndianWriter.WriteUInt32(buffer, ref offset, FileIndex); + FileTimeHelper.WriteFileTime(buffer, ref offset, CreationTime); + FileTimeHelper.WriteFileTime(buffer, ref offset, LastAccessTime); + FileTimeHelper.WriteFileTime(buffer, ref offset, LastWriteTime); + FileTimeHelper.WriteFileTime(buffer, ref offset, LastChangeTime); + LittleEndianWriter.WriteInt64(buffer, ref offset, EndOfFile); + LittleEndianWriter.WriteInt64(buffer, ref offset, AllocationSize); + LittleEndianWriter.WriteUInt32(buffer, ref offset, (uint)ExtFileAttributes); + LittleEndianWriter.WriteUInt32(buffer, ref offset, fileNameLength); + LittleEndianWriter.WriteUInt32(buffer, ref offset, EASize); + ByteWriter.WriteByte(buffer, ref offset, shortNameLength); + ByteWriter.WriteByte(buffer, ref offset, Reserved); + ByteWriter.WriteUTF16String(buffer, ref offset, ShortName, 12); + LittleEndianWriter.WriteUInt16(buffer, ref offset, Reserved2); + LittleEndianWriter.WriteUInt64(buffer, ref offset, FileID); + SMB1Helper.WriteSMBString(buffer, ref offset, isUnicode, FileName); + } + + public override int GetLength(bool isUnicode) + { + int length = FixedLength; + + if (isUnicode) + { + length += FileName.Length * 2 + 2; + } + else + { + length += FileName.Length + 1; + } + return length; + } + + public override FindInformationLevel InformationLevel + { + get + { + return FindInformationLevel.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO; + } + } + } +} diff --git a/SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDFullDirectoryInfo.cs b/SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDFullDirectoryInfo.cs new file mode 100644 index 0000000..627bea7 --- /dev/null +++ b/SMBLibrary/SMB1FileStore/Structures/FindInformation/FindFileIDFullDirectoryInfo.cs @@ -0,0 +1,101 @@ +/* Copyright (C) 2014-2017 Tal Aloni . All rights reserved. + * + * You can redistribute this program and/or modify it under the terms of + * the GNU Lesser Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using System.Text; +using Utilities; + +namespace SMBLibrary.SMB1 +{ + /// + /// SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO + /// + public class FindFileIDFullDirectoryInfo : FindInformation + { + public const int FixedLength = 80; + + public uint NextEntryOffset; + public uint FileIndex; // SHOULD be set to zero when sent in a response and SHOULD be ignored when received by the client + public DateTime? CreationTime; + public DateTime? LastAccessTime; + public DateTime? LastWriteTime; + public DateTime? LastAttrChangeTime; + public long EndOfFile; + public long AllocationSize; + public ExtendedFileAttributes ExtFileAttributes; + //uint FileNameLength; // In bytes, MUST exclude the null termination. + public uint EASize; + public uint Reserved; + public ulong FileID; + public string FileName; // OEM / Unicode character array. MUST be written as SMB_STRING, and read as fixed length string. + + public FindFileIDFullDirectoryInfo() : base(false) + { + } + + public FindFileIDFullDirectoryInfo(byte[] buffer, ref int offset, bool isUnicode) : base(false) + { + NextEntryOffset = LittleEndianReader.ReadUInt32(buffer, ref offset); + FileIndex = LittleEndianReader.ReadUInt32(buffer, ref offset); + CreationTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + LastAccessTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + LastWriteTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + LastAttrChangeTime = FileTimeHelper.ReadNullableFileTime(buffer, ref offset); + EndOfFile = LittleEndianReader.ReadInt64(buffer, ref offset); + AllocationSize = LittleEndianReader.ReadInt64(buffer, ref offset); + ExtFileAttributes = (ExtendedFileAttributes)LittleEndianReader.ReadUInt32(buffer, ref offset); + uint fileNameLength = LittleEndianReader.ReadUInt32(buffer, ref offset); + EASize = LittleEndianReader.ReadUInt32(buffer, ref offset); + Reserved = LittleEndianReader.ReadUInt32(buffer, ref offset); + FileID = LittleEndianReader.ReadUInt64(buffer, ref offset); + FileName = SMB1Helper.ReadFixedLengthString(buffer, ref offset, isUnicode, (int)fileNameLength); + } + + public override void WriteBytes(byte[] buffer, ref int offset, bool isUnicode) + { + uint fileNameLength = (byte)(isUnicode ? FileName.Length * 2 : FileName.Length); + + LittleEndianWriter.WriteUInt32(buffer, ref offset, NextEntryOffset); + LittleEndianWriter.WriteUInt32(buffer, ref offset, FileIndex); + FileTimeHelper.WriteFileTime(buffer, ref offset, CreationTime); + FileTimeHelper.WriteFileTime(buffer, ref offset, LastAccessTime); + FileTimeHelper.WriteFileTime(buffer, ref offset, LastWriteTime); + FileTimeHelper.WriteFileTime(buffer, ref offset, LastAttrChangeTime); + LittleEndianWriter.WriteInt64(buffer, ref offset, EndOfFile); + LittleEndianWriter.WriteInt64(buffer, ref offset, AllocationSize); + LittleEndianWriter.WriteUInt32(buffer, ref offset, (uint)ExtFileAttributes); + LittleEndianWriter.WriteUInt32(buffer, ref offset, fileNameLength); + LittleEndianWriter.WriteUInt32(buffer, ref offset, EASize); + LittleEndianWriter.WriteUInt32(buffer, ref offset, Reserved); + LittleEndianWriter.WriteUInt64(buffer, ref offset, FileID); + SMB1Helper.WriteSMBString(buffer, ref offset, isUnicode, FileName); + } + + public override int GetLength(bool isUnicode) + { + int length = FixedLength; + + if (isUnicode) + { + length += FileName.Length * 2 + 2; + } + else + { + length += FileName.Length + 1; + } + return length; + } + + public override FindInformationLevel InformationLevel + { + get + { + return FindInformationLevel.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO; + } + } + } +} diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj index 4ea0e13..3d80cd6 100644 --- a/SMBLibrary/SMBLibrary.csproj +++ b/SMBLibrary/SMBLibrary.csproj @@ -281,6 +281,8 @@ + + diff --git a/SMBLibrary/Server/SMB1/SMB1FileStoreHelper.QueryDirectory.cs b/SMBLibrary/Server/SMB1/SMB1FileStoreHelper.QueryDirectory.cs index 1250427..b351f67 100644 --- a/SMBLibrary/Server/SMB1/SMB1FileStoreHelper.QueryDirectory.cs +++ b/SMBLibrary/Server/SMB1/SMB1FileStoreHelper.QueryDirectory.cs @@ -138,6 +138,46 @@ namespace SMBLibrary.Server.SMB1 result.FileName = fileBothDirectoryInfo.FileName; return result; } + case FindInformationLevel.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: + { + FileIdFullDirectoryInformation fileIDFullDirectoryInfo = (FileIdFullDirectoryInformation)entry; + + FindFileIDFullDirectoryInfo result = new FindFileIDFullDirectoryInfo(); + result.FileIndex = fileIDFullDirectoryInfo.FileIndex; + result.CreationTime = fileIDFullDirectoryInfo.CreationTime; + result.LastAccessTime = fileIDFullDirectoryInfo.LastAccessTime; + result.LastWriteTime = fileIDFullDirectoryInfo.LastWriteTime; + result.LastAttrChangeTime = fileIDFullDirectoryInfo.LastWriteTime; + result.EndOfFile = fileIDFullDirectoryInfo.EndOfFile; + result.AllocationSize = fileIDFullDirectoryInfo.AllocationSize; + result.ExtFileAttributes = (ExtendedFileAttributes)fileIDFullDirectoryInfo.FileAttributes; + result.EASize = fileIDFullDirectoryInfo.EaSize; + result.Reserved = fileIDFullDirectoryInfo.Reserved; + result.FileID = fileIDFullDirectoryInfo.FileId; + result.FileName = fileIDFullDirectoryInfo.FileName; + return result; + } + case FindInformationLevel.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: + { + FileIdBothDirectoryInformation fileIDBothDirectoryInfo = (FileIdBothDirectoryInformation)entry; + + FindFileIDBothDirectoryInfo result = new FindFileIDBothDirectoryInfo(); + result.FileIndex = fileIDBothDirectoryInfo.FileIndex; + result.CreationTime = fileIDBothDirectoryInfo.CreationTime; + result.LastAccessTime = fileIDBothDirectoryInfo.LastAccessTime; + result.LastWriteTime = fileIDBothDirectoryInfo.LastWriteTime; + result.LastChangeTime = fileIDBothDirectoryInfo.LastWriteTime; + result.EndOfFile = fileIDBothDirectoryInfo.EndOfFile; + result.AllocationSize = fileIDBothDirectoryInfo.AllocationSize; + result.ExtFileAttributes = (ExtendedFileAttributes)fileIDBothDirectoryInfo.FileAttributes; + result.EASize = fileIDBothDirectoryInfo.EaSize; + result.Reserved = fileIDBothDirectoryInfo.Reserved1; + result.ShortName = fileIDBothDirectoryInfo.ShortName; + result.Reserved2 = fileIDBothDirectoryInfo.Reserved2; + result.FileID = fileIDBothDirectoryInfo.FileId; + result.FileName = fileIDBothDirectoryInfo.FileName; + return result; + } default: { throw new UnsupportedInformationLevelException(); diff --git a/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs b/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs index 108c8a8..64a97ef 100644 --- a/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs +++ b/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs @@ -282,12 +282,6 @@ namespace SMBLibrary.Server.SMB1 { switch (informationLevel) { - case FindInformationLevel.SMB_INFO_STANDARD: - return FileInformationClass.FileDirectoryInformation; - case FindInformationLevel.SMB_INFO_QUERY_EA_SIZE: - return FileInformationClass.FileFullDirectoryInformation; - case FindInformationLevel.SMB_INFO_QUERY_EAS_FROM_LIST: - return FileInformationClass.FileDirectoryInformation; case FindInformationLevel.SMB_FIND_FILE_DIRECTORY_INFO: return FileInformationClass.FileDirectoryInformation; case FindInformationLevel.SMB_FIND_FILE_FULL_DIRECTORY_INFO: @@ -296,6 +290,10 @@ namespace SMBLibrary.Server.SMB1 return FileInformationClass.FileNamesInformation; case FindInformationLevel.SMB_FIND_FILE_BOTH_DIRECTORY_INFO: return FileInformationClass.FileBothDirectoryInformation; + case FindInformationLevel.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: + return FileInformationClass.FileIdFullDirectoryInformation; + case FindInformationLevel.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: + return FileInformationClass.FileIdBothDirectoryInformation; default: throw new UnsupportedInformationLevelException(); }