OpenAndXHelper will now call NTFileSystemHelper.CreateFile

This commit is contained in:
Tal Aloni 2017-02-11 01:21:23 +02:00
parent 756fbb96fa
commit 7e6ad281b1
2 changed files with 187 additions and 111 deletions

View file

@ -39,11 +39,12 @@ namespace SMBLibrary
STATUS_USER_SESSION_DELETED = 0xC0000203, STATUS_USER_SESSION_DELETED = 0xC0000203,
STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205, STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205,
STATUS_INVALID_SMB = 0x00010002, // SMB1/CIFS: A corrupt or invalid SMB request was received STATUS_INVALID_SMB = 0x00010002, // SMB1/CIFS: A corrupt or invalid SMB request was received
STATUS_SMB_BAD_COMMAND = 0x00160002, // SMB1/CIFS: An unknown SMB command code was received by the server STATUS_SMB_BAD_COMMAND = 0x00160002, // SMB1/CIFS: An unknown SMB command code was received by the server
STATUS_SMB_BAD_FID = 0x00060001, // SMB1/CIFS STATUS_SMB_BAD_FID = 0x00060001, // SMB1/CIFS
STATUS_SMB_BAD_TID = 0x00050002, // SMB1/CIFS STATUS_SMB_BAD_TID = 0x00050002, // SMB1/CIFS
STATUS_OS2_NO_MORE_SIDS = 0x00710001, // SMB1/CIFS STATUS_OS2_INVALID_ACCESS = 0x000C0001, // SMB1/CIFS
STATUS_OS2_INVALID_LEVEL = 0x007C0001, // SMB1/CIFS STATUS_OS2_NO_MORE_SIDS = 0x00710001, // SMB1/CIFS
STATUS_OS2_INVALID_LEVEL = 0x007C0001, // SMB1/CIFS
} }
} }

View file

@ -21,6 +21,23 @@ namespace SMBLibrary.Server.SMB1
SMB1Session session = state.GetSession(header.UID); SMB1Session session = state.GetSession(header.UID);
bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0; bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0;
string path = request.FileName; string path = request.FileName;
AccessMask desiredAccess;
ShareAccess shareAccess;
CreateDisposition createDisposition;
try
{
desiredAccess = ToAccessMask(request.AccessMode.AccessMode);
shareAccess = ToShareAccess(request.AccessMode.SharingMode);
createDisposition = ToCreateDisposition(request.OpenMode);
}
catch (ArgumentException)
{
// Invalid input according to MS-CIFS
header.Status = NTStatus.STATUS_OS2_INVALID_ACCESS;
return new ErrorResponse(request.CommandName);
}
CreateOptions createOptions = ToCreateOptions(request.AccessMode);
FileAccess fileAccess = ToFileAccess(request.AccessMode.AccessMode); FileAccess fileAccess = ToFileAccess(request.AccessMode.AccessMode);
if (share is FileSystemShare) if (share is FileSystemShare)
{ {
@ -31,117 +48,56 @@ namespace SMBLibrary.Server.SMB1
} }
} }
FileSystemEntry entry = null;
Stream stream = null;
FileStatus fileStatus;
if (share is NamedPipeShare) if (share is NamedPipeShare)
{ {
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path); Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
if (pipeStream != null) if (pipeStream == null)
{ {
ushort? fileID = session.AddOpenFile(path, pipeStream); header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
if (!fileID.HasValue) return new ErrorResponse(request.CommandName);
{
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
return new ErrorResponse(request.CommandName);
}
if (isExtended)
{
return CreateResponseExtendedForNamedPipe(fileID.Value);
}
else
{
return CreateResponseForNamedPipe(fileID.Value);
}
} }
fileStatus = FileStatus.FILE_OPENED;
header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
return new ErrorResponse(request.CommandName);
} }
else // FileSystemShare else // FileSystemShare
{ {
FileSystemShare fileSystemShare = (FileSystemShare)share; FileSystemShare fileSystemShare = (FileSystemShare)share;
IFileSystem fileSystem = fileSystemShare.FileSystem; IFileSystem fileSystem = fileSystemShare.FileSystem;
OpenResult openResult; header.Status = NTFileSystemHelper.CreateFile(out entry, out stream, out fileStatus, fileSystem, path, desiredAccess, shareAccess, createDisposition, createOptions, state);
FileSystemEntry entry = fileSystem.GetEntry(path); if (header.Status != NTStatus.STATUS_SUCCESS)
if (entry != null)
{ {
if (request.OpenMode.FileExistsOpts == FileExistsOpts.ReturnError) return new ErrorResponse(request.CommandName);
{ }
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION; }
return new ErrorResponse(request.CommandName);
} ushort? fileID = session.AddOpenFile(path, stream);
else if (request.OpenMode.FileExistsOpts == FileExistsOpts.TruncateToZero) if (!fileID.HasValue)
{ {
try if (stream != null)
{ {
Stream temp = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite); stream.Close();
temp.Close(); }
} header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
catch (IOException ex) return new ErrorResponse(request.CommandName);
{ }
ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION) OpenResult openResult = ToOpenResult(fileStatus);
{ if (share is NamedPipeShare)
header.Status = NTStatus.STATUS_SHARING_VIOLATION; {
return new ErrorResponse(request.CommandName); if (isExtended)
} {
else return CreateResponseExtendedForNamedPipe(fileID.Value, openResult);
{
header.Status = NTStatus.STATUS_DATA_ERROR;
return new ErrorResponse(request.CommandName);
}
}
catch (UnauthorizedAccessException)
{
header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(request.CommandName);
}
openResult = OpenResult.FileExistedAndWasTruncated;
}
else // FileExistsOpts.Append
{
openResult = OpenResult.FileExistedAndWasOpened;
}
} }
else else
{ {
if (request.OpenMode.CreateFile == CreateFile.ReturnErrorIfNotExist) return CreateResponseForNamedPipe(fileID.Value, openResult);
{
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
return new ErrorResponse(request.CommandName);
}
if ((request.FileAttrs & SMBFileAttributes.Directory) > 0)
{
state.LogToServer(Severity.Information, "OpenAndX: Creating directory '{0}'", path);
entry = fileSystem.CreateDirectory(path);
}
else
{
state.LogToServer(Severity.Information, "OpenAndX: Creating file '{0}'", path);
entry = fileSystem.CreateFile(path);
}
openResult = OpenResult.NotExistedAndWasCreated;
}
FileShare fileShare = ToFileShare(request.AccessMode.SharingMode);
Stream stream = null;
if (!entry.IsDirectory)
{
bool buffered = (request.AccessMode.CachedMode == CachedMode.CachingAllowed && request.AccessMode.WriteThroughMode == WriteThroughMode.Disabled);
state.LogToServer(Severity.Verbose, "OpenAndX: Opening '{0}', Access={1}, Share={2}, Buffered={3}", path, fileAccess, fileShare, buffered);
stream = fileSystem.OpenFile(path, FileMode.Open, fileAccess, fileShare);
if (buffered)
{
stream = new PrefetchedStream(stream);
}
}
ushort? fileID = session.AddOpenFile(path, stream);
if (!fileID.HasValue)
{
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
return new ErrorResponse(request.CommandName);
} }
}
else // FileSystemShare
{
if (isExtended) if (isExtended)
{ {
return CreateResponseExtendedFromFileSystemEntry(entry, fileID.Value, openResult); return CreateResponseExtendedFromFileSystemEntry(entry, fileID.Value, openResult);
@ -153,6 +109,30 @@ namespace SMBLibrary.Server.SMB1
} }
} }
private static AccessMask ToAccessMask(AccessMode accessMode)
{
if (accessMode == AccessMode.Read)
{
return FileAccessMask.GENERIC_READ;
}
if (accessMode == AccessMode.Write)
{
return FileAccessMask.GENERIC_WRITE | FileAccessMask.FILE_READ_ATTRIBUTES;
}
else if (accessMode == AccessMode.ReadWrite)
{
return FileAccessMask.GENERIC_READ | FileAccessMask.GENERIC_WRITE;
}
else if (accessMode == AccessMode.Execute)
{
return FileAccessMask.GENERIC_READ | FileAccessMask.GENERIC_EXECUTE;
}
else
{
throw new ArgumentException("Invalid AccessMode value");
}
}
private static FileAccess ToFileAccess(AccessMode accessMode) private static FileAccess ToFileAccess(AccessMode accessMode)
{ {
if (accessMode == AccessMode.Write) if (accessMode == AccessMode.Write)
@ -169,27 +149,120 @@ namespace SMBLibrary.Server.SMB1
} }
} }
private static FileShare ToFileShare(SharingMode sharingMode) private static ShareAccess ToShareAccess(SharingMode sharingMode)
{ {
if (sharingMode == SharingMode.DenyReadWriteExecute) if (sharingMode == SharingMode.Compatibility)
{ {
return FileShare.None; return ShareAccess.FILE_SHARE_READ;
}
else if (sharingMode == SharingMode.DenyReadWriteExecute)
{
return 0;
} }
else if (sharingMode == SharingMode.DenyWrite) else if (sharingMode == SharingMode.DenyWrite)
{ {
return FileShare.Read; return ShareAccess.FILE_SHARE_READ;
} }
else if (sharingMode == SharingMode.DenyReadExecute) else if (sharingMode == SharingMode.DenyReadExecute)
{ {
return FileShare.Write; return ShareAccess.FILE_SHARE_WRITE;
}
else if (sharingMode == SharingMode.DenyNothing)
{
return ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE;
}
else if (sharingMode == (SharingMode)0xFF)
{
return 0;
} }
else else
{ {
return FileShare.ReadWrite; throw new ArgumentException("Invalid SharingMode value");
} }
} }
private static OpenAndXResponse CreateResponseForNamedPipe(ushort fileID) private static CreateDisposition ToCreateDisposition(OpenMode openMode)
{
if (openMode.CreateFile == CreateFile.ReturnErrorIfNotExist)
{
if (openMode.FileExistsOpts == FileExistsOpts.ReturnError)
{
throw new ArgumentException("Invalid OpenMode combination");
}
else if (openMode.FileExistsOpts == FileExistsOpts.Append)
{
return CreateDisposition.FILE_OPEN;
}
else if (openMode.FileExistsOpts == FileExistsOpts.TruncateToZero)
{
return CreateDisposition.FILE_OVERWRITE;
}
}
else if (openMode.CreateFile == CreateFile.CreateIfNotExist)
{
if (openMode.FileExistsOpts == FileExistsOpts.ReturnError)
{
return CreateDisposition.FILE_CREATE;
}
else if (openMode.FileExistsOpts == FileExistsOpts.Append)
{
return CreateDisposition.FILE_OPEN_IF;
}
else if (openMode.FileExistsOpts == FileExistsOpts.TruncateToZero)
{
return CreateDisposition.FILE_OVERWRITE_IF;
}
}
throw new ArgumentException("Invalid OpenMode combination");
}
private static CreateOptions ToCreateOptions(AccessModeOptions accessModeOptions)
{
CreateOptions result = CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_COMPLETE_IF_OPLOCKED;
if (accessModeOptions.ReferenceLocality == ReferenceLocality.Sequential)
{
result |= CreateOptions.FILE_SEQUENTIAL_ONLY;
}
else if (accessModeOptions.ReferenceLocality == ReferenceLocality.Random)
{
result |= CreateOptions.FILE_RANDOM_ACCESS;
}
else if (accessModeOptions.ReferenceLocality == ReferenceLocality.RandomWithLocality)
{
result |= CreateOptions.FILE_RANDOM_ACCESS;
}
if (accessModeOptions.CachedMode == CachedMode.DoNotCacheFile)
{
result |= CreateOptions.FILE_NO_INTERMEDIATE_BUFFERING;
}
if (accessModeOptions.WriteThroughMode == WriteThroughMode.WriteThrough)
{
result |= CreateOptions.FILE_WRITE_THROUGH;
}
return result;
}
private static OpenResult ToOpenResult(FileStatus fileStatus)
{
if (fileStatus == FileStatus.FILE_OVERWRITTEN ||
fileStatus == FileStatus.FILE_SUPERSEDED)
{
return OpenResult.FileExistedAndWasTruncated;
}
else if (fileStatus == FileStatus.FILE_CREATED)
{
return OpenResult.NotExistedAndWasCreated;
}
else
{
return OpenResult.FileExistedAndWasOpened;
}
}
private static OpenAndXResponse CreateResponseForNamedPipe(ushort fileID, OpenResult openResult)
{ {
OpenAndXResponse response = new OpenAndXResponse(); OpenAndXResponse response = new OpenAndXResponse();
response.FID = fileID; response.FID = fileID;
@ -198,10 +271,11 @@ namespace SMBLibrary.Server.SMB1
response.NMPipeStatus.ICount = 255; response.NMPipeStatus.ICount = 255;
response.NMPipeStatus.ReadMode = ReadMode.MessageMode; response.NMPipeStatus.ReadMode = ReadMode.MessageMode;
response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe; response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe;
response.OpenResults.OpenResult = openResult;
return response; return response;
} }
private static OpenAndXResponseExtended CreateResponseExtendedForNamedPipe(ushort fileID) private static OpenAndXResponseExtended CreateResponseExtendedForNamedPipe(ushort fileID, OpenResult openResult)
{ {
OpenAndXResponseExtended response = new OpenAndXResponseExtended(); OpenAndXResponseExtended response = new OpenAndXResponseExtended();
response.FID = fileID; response.FID = fileID;
@ -210,12 +284,14 @@ namespace SMBLibrary.Server.SMB1
response.NMPipeStatus.ICount = 255; response.NMPipeStatus.ICount = 255;
response.NMPipeStatus.ReadMode = ReadMode.MessageMode; response.NMPipeStatus.ReadMode = ReadMode.MessageMode;
response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe; response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe;
response.OpenResults.OpenResult = openResult;
return response; return response;
} }
private static OpenAndXResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult) private static OpenAndXResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult)
{ {
OpenAndXResponse response = new OpenAndXResponse(); OpenAndXResponse response = new OpenAndXResponse();
response.FID = fileID;
if (entry.IsDirectory) if (entry.IsDirectory)
{ {
response.FileAttrs = SMBFileAttributes.Directory; response.FileAttrs = SMBFileAttributes.Directory;
@ -224,7 +300,6 @@ namespace SMBLibrary.Server.SMB1
{ {
response.FileAttrs = SMBFileAttributes.Normal; response.FileAttrs = SMBFileAttributes.Normal;
} }
response.FID = fileID;
response.LastWriteTime = entry.LastWriteTime; response.LastWriteTime = entry.LastWriteTime;
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size); response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ; response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
@ -236,6 +311,7 @@ namespace SMBLibrary.Server.SMB1
private static OpenAndXResponseExtended CreateResponseExtendedFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult) private static OpenAndXResponseExtended CreateResponseExtendedFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult)
{ {
OpenAndXResponseExtended response = new OpenAndXResponseExtended(); OpenAndXResponseExtended response = new OpenAndXResponseExtended();
response.FID = fileID;
if (entry.IsDirectory) if (entry.IsDirectory)
{ {
response.FileAttrs = SMBFileAttributes.Directory; response.FileAttrs = SMBFileAttributes.Directory;
@ -244,7 +320,6 @@ namespace SMBLibrary.Server.SMB1
{ {
response.FileAttrs = SMBFileAttributes.Normal; response.FileAttrs = SMBFileAttributes.Normal;
} }
response.FID = fileID;
response.LastWriteTime = entry.LastWriteTime; response.LastWriteTime = entry.LastWriteTime;
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size); response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ; response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;