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); } } }
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)); } } }