internal static SMBCommand GetTreeConnectResponse(SMBHeader header, TreeConnectAndXRequest request, StateObject state, ShareCollection shares) { bool isExtended = (request.Flags & TreeConnectFlags.ExtendedResponse) > 0; string relativePath = ServerPathUtils.GetRelativeServerPath(request.Path); if (String.Equals(relativePath, "\\IPC$", StringComparison.InvariantCultureIgnoreCase)) { header.TID = state.AddConnectedTree(relativePath); if (isExtended) { return(CreateTreeConnectResponseExtended(ServiceName.NamedPipe)); } else { return(CreateTreeConnectResponse(ServiceName.NamedPipe)); } } else { FileSystemShare share = shares.GetShareFromRelativePath(relativePath); if (share == null) { header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND; return(new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX)); } else { string userName = state.GetConnectedUserName(header.UID); if (!share.HasReadAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX)); } else { header.TID = state.AddConnectedTree(relativePath); if (isExtended) { return(CreateTreeConnectResponseExtended(ServiceName.DiskShare)); } else { return(CreateTreeConnectResponse(ServiceName.DiskShare)); } } } } }
internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2QueryFileInformationRequest subcommand, FileSystemShare share, StateObject state) { IFileSystem fileSystem = share.FileSystem; string openedFilePath = state.GetOpenedFilePath(subcommand.FID); if (openedFilePath == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } FileSystemEntry entry = fileSystem.GetEntry(openedFilePath); if (entry == null) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(null); } Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse(); response.QueryInfo = InfoHelper.FromFileSystemEntry(entry, subcommand.InformationLevel); return(response); }
internal static Transaction2QueryPathInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2QueryPathInformationRequest subcommand, FileSystemShare share) { IFileSystem fileSystem = share.FileSystem; string path = subcommand.FileName; FileSystemEntry entry = fileSystem.GetEntry(path); if (entry == null) { // Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND // Returning STATUS_NO_SUCH_FILE caused an issue when executing ImageX.exe from WinPE 3.0 (32-bit) header.Status = NTStatus.STATUS_OBJECT_NAME_NOT_FOUND; return(null); } Transaction2QueryPathInformationResponse response = new Transaction2QueryPathInformationResponse(); response.QueryInfo = InfoHelper.FromFileSystemEntry(entry, subcommand.InformationLevel); return(response); }
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 Transaction2QueryFSInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2QueryFSInformationRequest subcommand, FileSystemShare share) { Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse(); response.QueryFSInfo = InfoHelper.GetFSInformation(subcommand.InformationLevel, share.FileSystem); return(response); }
internal static Transaction2FindNext2Response GetSubcommandResponse(SMBHeader header, Transaction2FindNext2Request subcommand, FileSystemShare share, StateObject state) { Transaction2FindNext2Response response = new Transaction2FindNext2Response(); if (!state.OpenSearches.ContainsKey(subcommand.SID)) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0; List <FileSystemEntry> entries = state.OpenSearches[subcommand.SID]; for (int index = 0; index < entries.Count; 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; entries.RemoveRange(0, returnCount); state.OpenSearches[subcommand.SID] = entries; response.SearchCount = (ushort)returnCount; response.EndOfSearch = (returnCount == entries.Count) && (entries.Count <= subcommand.SearchCount); return(response); }
internal static SMBCommand GetNTCreateResponse(SMBHeader header, NTCreateAndXRequest request, object share, StateObject state) { bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0; string path = request.FileName; if (share is NamedPipeShare) { RemoteService service = ((NamedPipeShare)share).GetService(path); if (service != null) { ushort fileID = state.AddOpenedFile(path); if (isExtended) { return(CreateResponseExtendedForNamedPipe(fileID)); } else { return(CreateResponseForNamedPipe(fileID)); } } header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } else // FileSystemShare { FileSystemShare fileSystemShare = (FileSystemShare)share; IFileSystem fileSystem = fileSystemShare.FileSystem; bool forceDirectory = (request.CreateOptions & CreateOptions.FILE_DIRECTORY_FILE) > 0; bool forceFile = (request.CreateOptions & CreateOptions.FILE_NON_DIRECTORY_FILE) > 0; if (forceDirectory & (request.CreateDisposition != CreateDisposition.FILE_CREATE && request.CreateDisposition != CreateDisposition.FILE_OPEN && request.CreateDisposition != CreateDisposition.FILE_OPEN_IF)) { header.Status = NTStatus.STATUS_INVALID_PARAMETER; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } // Windows will try to access named streams (alternate data streams) regardless of the FILE_NAMED_STREAMS flag, we need to prevent this behaviour. if (path.Contains(":")) { // Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } FileSystemEntry entry = fileSystem.GetEntry(path); if (request.CreateDisposition == CreateDisposition.FILE_OPEN) { if (entry == null) { header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } if (entry.IsDirectory && forceFile) { header.Status = NTStatus.STATUS_FILE_IS_A_DIRECTORY; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } if (!entry.IsDirectory && forceDirectory) { // Not sure if that's the correct response header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } } else if (request.CreateDisposition == CreateDisposition.FILE_CREATE) { if (entry != null) { // File already exists, fail the request header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } string userName = state.GetConnectedUserName(header.UID); if (!fileSystemShare.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } try { if (forceDirectory) { entry = fileSystem.CreateDirectory(path); } else { entry = fileSystem.CreateFile(path); } } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } } else if (request.CreateDisposition == CreateDisposition.FILE_OPEN_IF || request.CreateDisposition == CreateDisposition.FILE_OVERWRITE || request.CreateDisposition == CreateDisposition.FILE_OVERWRITE_IF || request.CreateDisposition == CreateDisposition.FILE_SUPERSEDE) { entry = fileSystem.GetEntry(path); if (entry == null) { if (request.CreateDisposition == CreateDisposition.FILE_OVERWRITE) { header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } string userName = state.GetConnectedUserName(header.UID); if (!fileSystemShare.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } try { if (forceDirectory) { entry = fileSystem.CreateDirectory(path); } else { entry = fileSystem.CreateFile(path); } } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } } else { if (request.CreateDisposition == CreateDisposition.FILE_OVERWRITE || request.CreateDisposition == CreateDisposition.FILE_OVERWRITE_IF || request.CreateDisposition == CreateDisposition.FILE_SUPERSEDE) { string userName = state.GetConnectedUserName(header.UID); if (!fileSystemShare.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } // Truncate the file try { Stream stream = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite); stream.Close(); } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_NT_CREATE_ANDX)); } } } } else { throw new InvalidRequestException(); } bool isSequentialAccess = (request.CreateOptions & CreateOptions.FILE_SEQUENTIAL_ONLY) > 0; ushort fileID = state.AddOpenedFile(path, isSequentialAccess); if (isExtended) { NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileSystemEntry(entry, fileID); if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0) { response.OpLockLevel = OpLockLevel.BatchOpLockGranted; } return(response); } else { NTCreateAndXResponse response = CreateResponseFromFileSystemEntry(entry, fileID); if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0) { response.OpLockLevel = OpLockLevel.BatchOpLockGranted; } return(response); } } }
public static uint PerformWrite(SMBHeader header, object share, ushort FID, ulong offset, byte[] data, StateObject state) { OpenedFileObject openedFile = state.GetOpenedFileObject(FID); if (openedFile == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(0); } string openedFilePath = openedFile.Path; if (share is NamedPipeShare) { RemoteService service = ((NamedPipeShare)share).GetService(openedFilePath); if (service != null) { RPCPDU rpcRequest = RPCPDU.GetPDU(data); RPCPDU rpcReply = RemoteServiceHelper.GetRPCReply(rpcRequest, service); byte[] replyData = rpcReply.GetBytes(); state.StoreNamedPipeReply(FID, replyData); return((uint)data.Length); } // This code should not execute unless the SMB request (sequence) is invalid header.Status = NTStatus.STATUS_INVALID_SMB; return(0); } else // FileSystemShare { FileSystemShare fileSystemShare = (FileSystemShare)share; IFileSystem fileSystem = fileSystemShare.FileSystem; if (openedFile.IsSequentialAccess && openedFile.Cache.Length > 0) { openedFile.Cache = new byte[0]; // Empty cache } try { Stream stream = fileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); stream.Seek((long)offset, SeekOrigin.Begin); stream.Write(data, 0, data.Length); stream.Close(); return((uint)data.Length); } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_DISK_FULL) { header.Status = NTStatus.STATUS_DISK_FULL; return(0); } else if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(0); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(0); } } catch (ArgumentOutOfRangeException) { header.Status = NTStatus.STATUS_DATA_ERROR; return(0); } catch (UnauthorizedAccessException) { // The user may have tried to write to a readonly file header.Status = NTStatus.STATUS_ACCESS_DENIED; return(0); } } }
internal static SMBCommand GetDeleteDirectoryResponse(SMBHeader header, DeleteDirectoryRequest request, FileSystemShare share, StateObject state) { string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY)); } IFileSystem fileSystem = share.FileSystem; FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName); if (entry == null) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY)); } if (!entry.IsDirectory) { header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID; return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY)); } try { fileSystem.Delete(request.DirectoryName); return(new DeleteDirectoryResponse()); } catch (IOException) { header.Status = NTStatus.STATUS_CANNOT_DELETE; return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY)); } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY)); } }
internal static SMBCommand GetSetInformation2Response(SMBHeader header, SetInformation2Request request, FileSystemShare share, StateObject state) { string openedFilePath = state.GetOpenedFilePath(request.FID); if (openedFilePath == null) { header.Status = NTStatus.STATUS_SMB_BAD_FID; return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2)); } string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2)); } IFileSystem fileSystem = share.FileSystem; fileSystem.SetDates(openedFilePath, request.CreationDateTime, request.LastWriteDateTime, request.LastAccessDateTime); return(new SetInformation2Response()); }
internal static SMBCommand GetSetInformationResponse(SMBHeader header, SetInformationRequest request, FileSystemShare share, StateObject state) { string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2)); } IFileSystem fileSystem = share.FileSystem; FileSystemEntry entry = fileSystem.GetEntry(request.FileName); if (entry == null) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION)); } bool?isHidden = null; bool?isReadOnly = null; bool?isArchived = null; if ((request.FileAttributes & SMBLibrary.SMB1.FileAttributes.Hidden) > 0) { isHidden = true; } if ((request.FileAttributes & SMBLibrary.SMB1.FileAttributes.ReadOnly) > 0) { isReadOnly = true; } if ((request.FileAttributes & SMBLibrary.SMB1.FileAttributes.Archive) > 0) { isArchived = true; } fileSystem.SetAttributes(request.FileName, isHidden, isReadOnly, isArchived); if (request.LastWriteTime != SMBHelper.UTimeNotSpecified) { fileSystem.SetDates(request.FileName, null, request.LastWriteTime, null); } return(new SetInformationResponse()); }
internal static SMBCommand GetQueryInformationResponse(SMBHeader header, QueryInformationRequest request, FileSystemShare share) { IFileSystem fileSystem = share.FileSystem; FileSystemEntry entry = fileSystem.GetEntry(request.FileName); if (entry == null) { header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID; return(new ErrorResponse(CommandName.SMB_COM_QUERY_INFORMATION)); } QueryInformationResponse response = new QueryInformationResponse(); response.FileAttributes = InfoHelper.GetFileAttributes(entry); response.LastWriteTime = entry.LastWriteTime; response.FileSize = (uint)Math.Min(UInt32.MaxValue, entry.Size); return(response); }
internal static SMBCommand GetCreateDirectoryResponse(SMBHeader header, CreateDirectoryRequest request, FileSystemShare share, StateObject state) { string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY)); } IFileSystem fileSystem = share.FileSystem; try { fileSystem.CreateDirectory(request.DirectoryName); } catch (IOException) { header.Status = NTStatus.STATUS_OBJECT_NAME_INVALID; return(new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY)); } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY)); } return(new CreateDirectoryResponse()); }
internal static SMBCommand GetRenameResponse(SMBHeader header, RenameRequest request, FileSystemShare share, StateObject state) { string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_RENAME)); } IFileSystem fileSystem = share.FileSystem; FileSystemEntry sourceEntry = fileSystem.GetEntry(request.OldFileName); if (sourceEntry == null) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(new ErrorResponse(CommandName.SMB_COM_RENAME)); } // The file must not already exist unless we just want to upcase / downcase a filename letter FileSystemEntry destinationEntry = fileSystem.GetEntry(request.NewFileName); if (destinationEntry != null && !String.Equals(request.OldFileName, request.NewFileName, StringComparison.InvariantCultureIgnoreCase)) { // The new file already exists. header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION; return(new ErrorResponse(CommandName.SMB_COM_RENAME)); } try { fileSystem.Move(request.OldFileName, request.NewFileName); return(new RenameResponse()); } catch (IOException) { header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(new ErrorResponse(CommandName.SMB_COM_RENAME)); } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_RENAME)); } }
internal static Transaction2SetFileInformationResponse GetSubcommandResponse(SMBHeader header, Transaction2SetFileInformationRequest subcommand, FileSystemShare share, StateObject state) { string openedFilePath = state.GetOpenedFilePath(subcommand.FID); if (openedFilePath == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse(); switch (subcommand.InformationLevel) { case SetInformationLevel.SMB_INFO_STANDARD: { return(response); } case SetInformationLevel.SMB_INFO_SET_EAS: { throw new NotImplementedException(); } case SetInformationLevel.SMB_SET_FILE_BASIC_INFO: { string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } SetFileBasicInfo info = (SetFileBasicInfo)subcommand.SetInfo; bool isHidden = (info.ExtFileAttributes & ExtendedFileAttributes.Hidden) > 0; bool isReadonly = (info.ExtFileAttributes & ExtendedFileAttributes.Readonly) > 0; bool isArchived = (info.ExtFileAttributes & ExtendedFileAttributes.Archive) > 0; try { share.FileSystem.SetAttributes(openedFilePath, isHidden, isReadonly, isArchived); } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } DateTime?creationTime = null; DateTime?lastWriteDT = null; DateTime?lastAccessTime = null; if (info.CreationTime != SMBHelper.FileTimeNotSpecified) { creationTime = info.CreationTime; } if (info.LastWriteTime != SMBHelper.FileTimeNotSpecified) { lastWriteDT = info.LastWriteTime; } if (info.LastAccessTime != SMBHelper.FileTimeNotSpecified) { lastAccessTime = info.LastAccessTime; } try { share.FileSystem.SetDates(openedFilePath, creationTime, lastWriteDT, lastAccessTime); } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(null); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(null); } } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } return(response); } case SetInformationLevel.SMB_SET_FILE_DISPOSITION_INFO: { if (((SetFileDispositionInfo)subcommand.SetInfo).DeletePending) { // We're supposed to delete the file on close, but it's too late to report errors at this late stage string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(userName)) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } try { share.FileSystem.Delete(openedFilePath); } catch (IOException) { header.Status = NTStatus.STATUS_FILE_LOCK_CONFLICT; return(null); } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } } return(response); } case SetInformationLevel.SMB_SET_FILE_ALLOCATION_INFO: { // This subcommand is used to set the file length in bytes. // Note: the input will NOT be a multiple of the cluster size / bytes per sector. ulong allocationSize = ((SetFileAllocationInfo)subcommand.SetInfo).AllocationSize; try { Stream stream = share.FileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); stream.SetLength((long)allocationSize); stream.Close(); } catch { } return(response); } case SetInformationLevel.SMB_SET_FILE_END_OF_FILE_INFO: { ulong endOfFile = ((SetFileEndOfFileInfo)subcommand.SetInfo).EndOfFile; try { Stream stream = share.FileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); stream.SetLength((long)endOfFile); stream.Close(); } catch { } return(response); } default: { throw new InvalidRequestException(); } } }
internal static SMBCommand GetCompleteTransaction2Response(SMBHeader header, byte[] requestSetup, byte[] requestParameters, byte[] requestData, object share, StateObject state, List <SMBCommand> sendQueue) { Transaction2Subcommand subcommand = Transaction2Subcommand.GetSubcommandRequest(requestSetup, requestParameters, requestData, header.UnicodeFlag); Transaction2Subcommand subcommandResponse = null; if (!(share is FileSystemShare)) { header.Status = NTStatus.STATUS_SMB_BAD_COMMAND; return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION2)); } FileSystemShare fileSystemShare = (FileSystemShare)share; if (subcommand is Transaction2FindFirst2Request) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindFirst2Request)subcommand, fileSystemShare, state); } else if (subcommand is Transaction2FindNext2Request) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2FindNext2Request)subcommand, fileSystemShare, state); } else if (subcommand is Transaction2QueryFSInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFSInformationRequest)subcommand, fileSystemShare); } else if (subcommand is Transaction2QueryPathInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryPathInformationRequest)subcommand, fileSystemShare); } else if (subcommand is Transaction2SetPathInformationRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is Transaction2QueryFileInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2QueryFileInformationRequest)subcommand, fileSystemShare, state); } else if (subcommand is Transaction2SetFileInformationRequest) { subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2SetFileInformationRequest)subcommand, fileSystemShare, state); } else if (subcommand is Transaction2CreateDirectoryRequest) { header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; } else if (subcommand is Transaction2GetDfsReferralRequest) { header.Status = NTStatus.STATUS_NO_SUCH_DEVICE; } else { header.Status = NTStatus.STATUS_SMB_BAD_COMMAND; } if (header.Status != NTStatus.STATUS_SUCCESS) { return(new ErrorResponse(CommandName.SMB_COM_TRANSACTION2)); } byte[] responseSetup = subcommandResponse.GetSetup(); byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag); byte[] responseData = subcommandResponse.GetData(header.UnicodeFlag); Transaction2Response response = new Transaction2Response(); PrepareResponse(response, responseSetup, responseParameters, responseData, state.MaxBufferSize, sendQueue); return(response); }
internal static SMBCommand GetCheckDirectoryResponse(SMBHeader header, CheckDirectoryRequest request, FileSystemShare share) { IFileSystem fileSystem = share.FileSystem; FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName); if (entry == null || !entry.IsDirectory) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(new ErrorResponse(CommandName.SMB_COM_CHECK_DIRECTORY)); } return(new CheckDirectoryResponse()); }
public static byte[] PerformRead(SMBHeader header, object share, ushort FID, long offset, int maxCount, StateObject state) { OpenedFileObject openedFile = state.GetOpenedFileObject(FID); if (openedFile == null) { header.Status = NTStatus.STATUS_INVALID_HANDLE; return(null); } string openedFilePath = openedFile.Path; if (share is NamedPipeShare) { return(state.RetrieveNamedPipeReply(FID)); } else // FileSystemShare { FileSystemShare fileSystemShare = (FileSystemShare)share; IFileSystem fileSystem = fileSystemShare.FileSystem; if (openedFile.IsSequentialAccess) { bool isInCache = (offset >= openedFile.CacheOffset) && (offset + maxCount <= openedFile.CacheOffset + openedFile.Cache.Length); if (!isInCache) { int bytesRead; try { Stream stream = fileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); stream.Seek(offset, SeekOrigin.Begin); openedFile.CacheOffset = offset; openedFile.Cache = new byte[OpenedFileObject.CacheSize]; bytesRead = stream.Read(openedFile.Cache, 0, OpenedFileObject.CacheSize); stream.Close(); } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(null); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(null); } } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } if (bytesRead < OpenedFileObject.CacheSize) { // EOF, we must trim the response data array byte[] buffer = new byte[bytesRead]; Array.Copy(openedFile.Cache, 0, buffer, 0, bytesRead); openedFile.Cache = buffer; } } int offsetInCache = (int)(offset - openedFile.CacheOffset); int bytesRemained = openedFile.Cache.Length - offsetInCache; int dataLength = Math.Min(maxCount, bytesRemained); byte[] data = new byte[dataLength]; Array.Copy(openedFile.Cache, offsetInCache, data, 0, dataLength); return(data); } else { int bytesRead; byte[] data; try { Stream stream = fileSystem.OpenFile(openedFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); stream.Seek(offset, SeekOrigin.Begin); data = new byte[maxCount]; bytesRead = stream.Read(data, 0, maxCount); stream.Close(); } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(null); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(null); } } catch (ArgumentOutOfRangeException) { header.Status = NTStatus.STATUS_DATA_ERROR; return(null); } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(null); } if (bytesRead < maxCount) { // EOF, we must trim the response data array byte[] buffer = new byte[bytesRead]; Array.Copy(data, 0, buffer, 0, bytesRead); data = buffer; } return(data); } } }
internal static SMBCommand GetOpenAndXResponse(SMBHeader header, OpenAndXRequest request, object share, StateObject state) { bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0; string path = request.FileName; if (share is NamedPipeShare) { RemoteService service = ((NamedPipeShare)share).GetService(path); if (service != null) { ushort fileID = state.AddOpenedFile(path); if (isExtended) { return(CreateResponseExtendedForNamedPipe(fileID)); } else { CreateResponseForNamedPipe(fileID); } } header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND; return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX)); } else // FileSystemShare { FileSystemShare fileSystemShare = (FileSystemShare)share; string userName = state.GetConnectedUserName(header.UID); bool hasWriteAccess = fileSystemShare.HasWriteAccess(userName); IFileSystem fileSystem = fileSystemShare.FileSystem; OpenResult openResult; FileSystemEntry entry = fileSystem.GetEntry(path); if (entry != null) { if (!hasWriteAccess && request.AccessMode.AccessMode == AccessMode.Write || request.AccessMode.AccessMode == AccessMode.ReadWrite) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX)); } if (request.OpenMode.FileExistsOpts == FileExistsOpts.ReturnError) { header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION; return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX)); } else if (request.OpenMode.FileExistsOpts == FileExistsOpts.TruncateToZero) { try { Stream stream = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite); stream.Close(); } catch (IOException ex) { ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex); if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) { header.Status = NTStatus.STATUS_SHARING_VIOLATION; return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX)); } else { header.Status = NTStatus.STATUS_DATA_ERROR; return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX)); } } catch (UnauthorizedAccessException) { header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX)); } openResult = OpenResult.FileExistedAndWasTruncated; } else // FileExistsOpts.Append { openResult = OpenResult.FileExistedAndWasOpened; } } else { if (request.OpenMode.CreateFile == CreateFile.ReturnErrorIfNotExist) { header.Status = NTStatus.STATUS_NO_SUCH_FILE; return(new ErrorResponse(CommandName.SMB_COM_OPEN_ANDX)); } entry = fileSystem.CreateFile(path); openResult = OpenResult.NotExistedAndWasCreated; } ushort fileID = state.AddOpenedFile(path, true); if (isExtended) { return(CreateResponseFromFileSystemEntry(entry, fileID, openResult)); } else { return(CreateResponseExtendedFromFileSystemEntry(entry, fileID, openResult)); } } }