internal static Transaction2FindFirst2Response GetSubcommandResponse(SMBHeader header, Transaction2FindFirst2Request subcommand, FileSystemShare share, StateObject state) { IFileSystem fileSystem = share.FileSystem; Transaction2FindFirst2Response response = new Transaction2FindFirst2Response(); string path = subcommand.FileName; // '\Directory' - Get the directory info // '\Directory\*' - List the directory files // '\Directory\s*' - List the directory files starting with s (cmd.exe will use this syntax when entering 's' and hitting tab for autocomplete) // '\Directory\<.inf' (Update driver will use this syntax) // '\Directory\exefile"*' (cmd.exe will use this syntax when entering an exe without its extension, explorer will use this opening a directory from the run menu) bool isDirectoryEnumeration = false; string searchPattern = String.Empty; if (path.Contains("*") || path.Contains("<")) { isDirectoryEnumeration = true; int separatorIndex = path.LastIndexOf('\\'); searchPattern = path.Substring(separatorIndex + 1); path = path.Substring(0, separatorIndex + 1); } bool exactNameWithoutExtension = searchPattern.Contains("\""); FileSystemEntry entry = fileSystem.GetEntry(path); if (entry == null) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(null); } List <FileSystemEntry> entries; if (isDirectoryEnumeration) { try { entries = fileSystem.ListEntriesInDirectory(path); } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } if (searchPattern != String.Empty) { entries = GetFiltered(entries, searchPattern); } if (!exactNameWithoutExtension) { if (IncludeParentDirectoryInResults) { entries.Insert(0, fileSystem.GetEntry(FileSystem.GetParentDirectory(path))); entries[0].Name = ".."; } if (IncludeCurrentDirectoryInResults) { entries.Insert(0, fileSystem.GetEntry(path)); entries[0].Name = "."; } } // If no matching entries are found, the server SHOULD fail the request with STATUS_NO_SUCH_FILE. if (entries.Count == 0) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(null); } } else { entries = new List <FileSystemEntry>(); entries.Add(entry); } bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0; int entriesToReturn = Math.Min(subcommand.SearchCount, entries.Count); // We ignore SearchAttributes for (int index = 0; index < entriesToReturn; index++) { FindInformationEntry infoEntry = InfoHelper.FromFileSystemEntry(entries[index], subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys); response.FindInfoList.Add(infoEntry); if (response.FindInfoList.GetLength(header.UnicodeFlag) > state.GetMaxDataCount(header.PID)) { response.FindInfoList.RemoveAt(response.FindInfoList.Count - 1); break; } } int returnCount = response.FindInfoList.Count; response.EndOfSearch = (returnCount == entries.Count) && (entries.Count <= subcommand.SearchCount); response.SID = state.AllocateSearchHandle(); entries.RemoveRange(0, returnCount); state.OpenSearches.Add(response.SID, entries); return(response); }
internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, uint maxDataCount, Transaction2FindFirst2Request subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); string fileNamePattern = subcommand.FileName; if (!fileNamePattern.StartsWith(@"\")) { fileNamePattern = @"\" + fileNamePattern; } List <QueryDirectoryFileInformation> entries; FileInformationClass informationClass; try { informationClass = FindInformationHelper.ToFileInformationClass(subcommand.InformationLevel); } catch (UnsupportedInformationLevelException) { state.LogToServer(Severity.Verbose, "FindFirst2: Unsupported information level: {0}.", subcommand.InformationLevel); header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL; return(null); } NTStatus searchStatus = SMB1FileStoreHelper.QueryDirectory(out entries, share.FileStore, fileNamePattern, informationClass, session.SecurityContext); if (searchStatus != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}{1}', NTStatus: {2}", share.Name, fileNamePattern, searchStatus.ToString()); header.Status = searchStatus; return(null); } // We ignore SearchAttributes state.LogToServer(Severity.Information, "FindFirst2: Searched for '{0}{1}', found {2} matching entries", share.Name, fileNamePattern, entries.Count); // [MS-CIFS] If no matching entries are found, the server SHOULD fail the request with STATUS_NO_SUCH_FILE. if (entries.Count == 0) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(null); } 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)maxDataCount; FindInformationList findInformationList; try { findInformationList = FindInformationHelper.ToFindInformationList(segment, header.UnicodeFlag, maxLength); } catch (UnsupportedInformationLevelException) { state.LogToServer(Severity.Verbose, "FindFirst2: Unsupported information level: {0}.", subcommand.InformationLevel); header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL; return(null); } int returnCount = findInformationList.Count; Transaction2FindFirst2Response response = new Transaction2FindFirst2Response(); response.SetFindInformationList(findInformationList, header.UnicodeFlag); response.EndOfSearch = (returnCount == entries.Count); // If [..] the search fit within a single response and SMB_FIND_CLOSE_AT_EOS is set in the Flags field, // or if SMB_FIND_CLOSE_AFTER_REQUEST is set in the request, // the server SHOULD return a SID field value of zero. // This indicates that the search has been closed and is no longer active on the server. if ((response.EndOfSearch && subcommand.CloseAtEndOfSearch) || subcommand.CloseAfterRequest) { response.SID = 0; } else { ushort?searchHandle = session.AddOpenSearch(entries, returnCount); if (!searchHandle.HasValue) { header.Status = NTStatus.STATUS_OS2_NO_MORE_SIDS; return(null); } response.SID = searchHandle.Value; } return(response); }
public NTStatus QueryDirectory(out List <FindInformation> result, string fileName, FindInformationLevel informationLevel) { result = null; int maxOutputLength = 4096; Transaction2FindFirst2Request subcommand = new Transaction2FindFirst2Request(); subcommand.SearchAttributes = SMBFileAttributes.Hidden | SMBFileAttributes.System | SMBFileAttributes.Directory; subcommand.SearchCount = UInt16.MaxValue; subcommand.Flags = FindFlags.SMB_FIND_CLOSE_AT_EOS; subcommand.InformationLevel = informationLevel; subcommand.FileName = fileName; Transaction2Request request = new Transaction2Request(); request.Setup = subcommand.GetSetup(); request.TransParameters = subcommand.GetParameters(m_client.Unicode); request.TransData = subcommand.GetData(m_client.Unicode); request.TotalDataCount = (ushort)request.TransData.Length; request.TotalParameterCount = (ushort)request.TransParameters.Length; request.MaxParameterCount = Transaction2FindFirst2Response.ParametersLength; request.MaxDataCount = (ushort)maxOutputLength; TrySendMessage(request); SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2); if (reply != null) { if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is Transaction2Response) { result = new List <FindInformation>(); Transaction2Response response = (Transaction2Response)reply.Commands[0]; Transaction2FindFirst2Response subcommandResponse = new Transaction2FindFirst2Response(response.TransParameters, response.TransData, reply.Header.UnicodeFlag); FindInformationList findInformationList = subcommandResponse.GetFindInformationList(subcommand.InformationLevel, reply.Header.UnicodeFlag); result.AddRange(findInformationList); bool endOfSearch = subcommandResponse.EndOfSearch; while (!endOfSearch) { Transaction2FindNext2Request nextSubcommand = new Transaction2FindNext2Request(); nextSubcommand.SID = subcommandResponse.SID; nextSubcommand.SearchCount = UInt16.MaxValue; nextSubcommand.Flags = FindFlags.SMB_FIND_CLOSE_AT_EOS | FindFlags.SMB_FIND_CONTINUE_FROM_LAST; nextSubcommand.InformationLevel = informationLevel; nextSubcommand.FileName = fileName; request = new Transaction2Request(); request.Setup = nextSubcommand.GetSetup(); request.TransParameters = nextSubcommand.GetParameters(m_client.Unicode); request.TransData = nextSubcommand.GetData(m_client.Unicode); request.TotalDataCount = (ushort)request.TransData.Length; request.TotalParameterCount = (ushort)request.TransParameters.Length; request.MaxParameterCount = Transaction2FindNext2Response.ParametersLength; request.MaxDataCount = (ushort)maxOutputLength; TrySendMessage(request); reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2); if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is Transaction2Response) { response = (Transaction2Response)reply.Commands[0]; Transaction2FindNext2Response nextSubcommandResponse = new Transaction2FindNext2Response(response.TransParameters, response.TransData, reply.Header.UnicodeFlag); findInformationList = nextSubcommandResponse.GetFindInformationList(subcommand.InformationLevel, reply.Header.UnicodeFlag); result.AddRange(findInformationList); endOfSearch = nextSubcommandResponse.EndOfSearch; } else { endOfSearch = true; } } } return(reply.Header.Status); } return(NTStatus.STATUS_INVALID_SMB); }
public void QueryDirectory(out List <FindInformation>?result, string fileName, FindInformationLevel informationLevel) { result = null; int maxOutputLength = 4096; Transaction2FindFirst2Request subCommand = new Transaction2FindFirst2Request { SearchAttributes = SMBFileAttributes.Hidden | SMBFileAttributes.System | SMBFileAttributes.Directory, SearchCount = ushort.MaxValue, Flags = FindFlags.SMB_FIND_CLOSE_AT_EOS, InformationLevel = informationLevel, FileName = fileName }; Transaction2Request request = new Transaction2Request { Setup = subCommand.GetSetup(), TransParameters = subCommand.GetParameters(m_client.Unicode), TransData = subCommand.GetData(m_client.Unicode) }; request.TotalDataCount = (ushort)request.TransData.Length; request.TotalParameterCount = (ushort)request.TransParameters.Length; request.MaxParameterCount = Transaction2FindFirst2Response.ParametersLength; request.MaxDataCount = (ushort)maxOutputLength; TrySendMessage(request); SMB1Message reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2); reply.IsSuccessElseThrow(); if (!(reply.Commands[0] is Transaction2Response)) { throw new NtStatusException(reply.Header.Status); } result = new List <FindInformation>(); Transaction2Response response = (Transaction2Response)reply.Commands[0]; Transaction2FindFirst2Response subcommandResponse = new Transaction2FindFirst2Response(response.TransParameters, response.TransData); FindInformationList findInformationList = subcommandResponse.GetFindInformationList(subCommand.InformationLevel, reply.Header.UnicodeFlag); result.AddRange(findInformationList); bool endOfSearch = subcommandResponse.EndOfSearch; while (!endOfSearch) { Transaction2FindNext2Request nextSubCommand = new Transaction2FindNext2Request { SID = subcommandResponse.SID, SearchCount = ushort.MaxValue, Flags = FindFlags.SMB_FIND_CLOSE_AT_EOS | FindFlags.SMB_FIND_CONTINUE_FROM_LAST, InformationLevel = informationLevel, FileName = fileName }; request = new Transaction2Request { Setup = nextSubCommand.GetSetup(), TransParameters = nextSubCommand.GetParameters(m_client.Unicode), TransData = nextSubCommand.GetData(m_client.Unicode) }; request.TotalDataCount = (ushort)request.TransData.Length; request.TotalParameterCount = (ushort)request.TransParameters.Length; request.MaxParameterCount = Transaction2FindNext2Response.ParametersLength; request.MaxDataCount = (ushort)maxOutputLength; TrySendMessage(request); reply = m_client.WaitForMessage(CommandName.SMB_COM_TRANSACTION2); if (reply.Header.Status == NTStatus.STATUS_SUCCESS && reply.Commands[0] is Transaction2Response transaction2Response) { Transaction2FindNext2Response nextSubCommandResponse = new Transaction2FindNext2Response(transaction2Response.TransParameters, transaction2Response.TransData); findInformationList = nextSubCommandResponse.GetFindInformationList(subCommand.InformationLevel, reply.Header.UnicodeFlag); result.AddRange(findInformationList); endOfSearch = nextSubCommandResponse.EndOfSearch; } else { endOfSearch = true; } } reply.IsSuccessElseThrow(); }