private static NTCreateAndXResponseExtended CreateResponseExtendedFromFileInformation(FileNetworkOpenInformation fileInfo, ushort fileID, FileStatus fileStatus) { NTCreateAndXResponseExtended response = new NTCreateAndXResponseExtended(); response.FID = fileID; response.CreateDisposition = ToCreateDisposition(fileStatus); response.CreateTime = fileInfo.CreationTime; response.LastAccessTime = fileInfo.LastAccessTime; response.LastWriteTime = fileInfo.LastWriteTime; response.LastChangeTime = fileInfo.LastWriteTime; response.ExtFileAttributes = (ExtendedFileAttributes)fileInfo.FileAttributes; response.AllocationSize = fileInfo.AllocationSize; response.EndOfFile = fileInfo.EndOfFile; response.ResourceType = ResourceType.FileTypeDisk; response.FileStatusFlags = FileStatusFlags.NO_EAS | FileStatusFlags.NO_SUBSTREAMS | FileStatusFlags.NO_REPARSETAG; response.Directory = fileInfo.IsDirectory; response.MaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA | FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA | FileAccessMask.FILE_EXECUTE | FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES | FileAccessMask.DELETE | FileAccessMask.READ_CONTROL | FileAccessMask.WRITE_DAC | FileAccessMask.WRITE_OWNER | FileAccessMask.SYNCHRONIZE; response.GuestMaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA | FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES | FileAccessMask.READ_CONTROL | FileAccessMask.SYNCHRONIZE; return(response); }
private static NTCreateAndXResponseExtended CreateResponseExtendedForNamedPipe(ushort fileID, FileStatus fileStatus) { NTCreateAndXResponseExtended response = new NTCreateAndXResponseExtended(); response.FID = fileID; response.CreateDisposition = ToCreateDisposition(fileStatus); response.ExtFileAttributes = ExtendedFileAttributes.Normal; response.ResourceType = ResourceType.FileTypeMessageModePipe; NamedPipeStatus status = new NamedPipeStatus(); status.ICount = 255; status.ReadMode = ReadMode.MessageMode; status.NamedPipeType = NamedPipeType.MessageNodePipe; response.NMPipeStatus = status; response.MaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA | FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA | FileAccessMask.FILE_EXECUTE | FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES | FileAccessMask.DELETE | FileAccessMask.READ_CONTROL | FileAccessMask.WRITE_DAC | FileAccessMask.WRITE_OWNER | FileAccessMask.SYNCHRONIZE; response.GuestMaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA | FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES | FileAccessMask.READ_CONTROL | FileAccessMask.SYNCHRONIZE; return(response); }
private static NTCreateAndXResponseExtended CreateResponseExtendedFromFileSystemEntry(FileSystemEntry entry, ushort fileID) { NTCreateAndXResponseExtended response = new NTCreateAndXResponseExtended(); if (entry.IsDirectory) { response.ExtFileAttributes = ExtendedFileAttributes.Directory; response.Directory = true; } else { response.ExtFileAttributes = ExtendedFileAttributes.Normal; } response.FID = fileID; response.CreateTime = entry.CreationTime; response.LastAccessTime = entry.LastAccessTime; response.LastWriteTime = entry.LastWriteTime; response.LastChangeTime = entry.LastWriteTime; response.CreateDisposition = CreateDisposition.FILE_OPEN; response.AllocationSize = InfoHelper.GetAllocationSize(entry.Size); response.EndOfFile = entry.Size; response.ResourceType = ResourceType.FileTypeDisk; response.FileStatus = FileStatus.NO_EAS | FileStatus.NO_SUBSTREAMS | FileStatus.NO_REPARSETAG; response.MaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA | FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA | FileAccessMask.FILE_EXECUTE | FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES | FileAccessMask.DELETE | FileAccessMask.READ_CONTROL | FileAccessMask.WRITE_DAC | FileAccessMask.WRITE_OWNER | FileAccessMask.SYNCHRONIZE; response.GuestMaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA | FileAccessMask.FILE_READ_ATTRIBUTES | FileAccessMask.FILE_WRITE_ATTRIBUTES | FileAccessMask.READ_CONTROL | FileAccessMask.SYNCHRONIZE; return(response); }
internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0; string path = request.FileName; FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition); if (share is FileSystemShare) { if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess)) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } object handle; FileStatus fileStatus; NTStatus createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext); if (createStatus != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: '{2}'.", share.Name, path, createStatus); header.Status = createStatus; return(new ErrorResponse(request.CommandName)); } state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}'.", share.Name, path); ushort?fileID = session.AddOpenFile(header.TID, path, handle); if (!fileID.HasValue) { share.FileStore.CloseFile(handle); header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; return(new ErrorResponse(request.CommandName)); } if (share is NamedPipeShare) { if (isExtended) { return(CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } else { return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } } else // FileSystemShare { FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle); if (isExtended) { NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileInformation(fileInfo, fileID.Value, fileStatus); if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0) { response.OpLockLevel = OpLockLevel.BatchOpLockGranted; } return(response); } else { NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus); if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0) { response.OpLockLevel = OpLockLevel.BatchOpLockGranted; } return(response); } } }
internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0; string path = request.FileName; if (!path.StartsWith(@"\")) { path = @"\" + path; } FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition); if (share is FileSystemShare) { if (!((FileSystemShare)share).HasAccess(session.SecurityContext, path, createAccess)) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. User '{2}' was denied access.", share.Name, request.FileName, session.UserName); header.Status = NTStatus.STATUS_ACCESS_DENIED; return(new ErrorResponse(request.CommandName)); } } object handle; FileStatus fileStatus; FileAttributes fileAttributes = ToFileAttributes(request.ExtFileAttributes); // GetFileInformation/FileNetworkOpenInformation requires FILE_READ_ATTRIBUTES AccessMask desiredAccess = request.DesiredAccess | (AccessMask)FileAccessMask.FILE_READ_ATTRIBUTES; NTStatus createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, desiredAccess, fileAttributes, request.ShareAccess, request.CreateDisposition, request.CreateOptions, session.SecurityContext); if (createStatus != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. NTStatus: {2}.", share.Name, path, createStatus); header.Status = createStatus; return(new ErrorResponse(request.CommandName)); } FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(desiredAccess); ushort? fileID = session.AddOpenFile(header.TID, share.Name, path, handle, fileAccess); if (!fileID.HasValue) { share.FileStore.CloseFile(handle); state.LogToServer(Severity.Verbose, "Create: Opening '{0}{1}' failed. Too many open files.", share.Name, path); header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; return(new ErrorResponse(request.CommandName)); } string fileAccessString = fileAccess.ToString().Replace(", ", "|"); string shareAccessString = request.ShareAccess.ToString().Replace(", ", "|"); state.LogToServer(Severity.Verbose, "Create: Opened '{0}{1}', FileAccess: {2}, ShareAccess: {3}. (UID: {4}, TID: {5}, FID: {6})", share.Name, path, fileAccessString, shareAccessString, header.UID, header.TID, fileID.Value); if (share is NamedPipeShare) { if (isExtended) { return(CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } else { return(CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED)); } } else // FileSystemShare { FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle); if (isExtended) { NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileInformation(fileInfo, fileID.Value, fileStatus); return(response); } else { NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus); 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); } } }