mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-04-30 10:47:48 +02:00
OpenAndXHelper will now call NTFileSystemHelper.CreateFile
This commit is contained in:
parent
756fbb96fa
commit
7e6ad281b1
2 changed files with 187 additions and 111 deletions
|
@ -43,6 +43,7 @@ namespace SMBLibrary
|
|||
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_TID = 0x00050002, // SMB1/CIFS
|
||||
STATUS_OS2_INVALID_ACCESS = 0x000C0001, // SMB1/CIFS
|
||||
STATUS_OS2_NO_MORE_SIDS = 0x00710001, // SMB1/CIFS
|
||||
STATUS_OS2_INVALID_LEVEL = 0x007C0001, // SMB1/CIFS
|
||||
}
|
||||
|
|
|
@ -21,6 +21,23 @@ namespace SMBLibrary.Server.SMB1
|
|||
SMB1Session session = state.GetSession(header.UID);
|
||||
bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0;
|
||||
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);
|
||||
if (share is FileSystemShare)
|
||||
{
|
||||
|
@ -31,117 +48,56 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
}
|
||||
|
||||
FileSystemEntry entry = null;
|
||||
Stream stream = null;
|
||||
FileStatus fileStatus;
|
||||
if (share is NamedPipeShare)
|
||||
{
|
||||
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
||||
if (pipeStream != null)
|
||||
if (pipeStream == null)
|
||||
{
|
||||
ushort? fileID = session.AddOpenFile(path, pipeStream);
|
||||
if (!fileID.HasValue)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if (isExtended)
|
||||
{
|
||||
return CreateResponseExtendedForNamedPipe(fileID.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateResponseForNamedPipe(fileID.Value);
|
||||
}
|
||||
}
|
||||
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
fileStatus = FileStatus.FILE_OPENED;
|
||||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||
|
||||
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
||||
|
||||
OpenResult openResult;
|
||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
||||
if (entry != null)
|
||||
header.Status = NTFileSystemHelper.CreateFile(out entry, out stream, out fileStatus, fileSystem, path, desiredAccess, shareAccess, createDisposition, createOptions, state);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
if (request.OpenMode.FileExistsOpts == FileExistsOpts.ReturnError)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
else if (request.OpenMode.FileExistsOpts == FileExistsOpts.TruncateToZero)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream temp = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
temp.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(request.CommandName);
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
{
|
||||
if (request.OpenMode.CreateFile == CreateFile.ReturnErrorIfNotExist)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
OpenResult openResult = ToOpenResult(fileStatus);
|
||||
if (share is NamedPipeShare)
|
||||
{
|
||||
if (isExtended)
|
||||
{
|
||||
return CreateResponseExtendedForNamedPipe(fileID.Value, openResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateResponseForNamedPipe(fileID.Value, openResult);
|
||||
}
|
||||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
if (isExtended)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return FileShare.Read;
|
||||
return ShareAccess.FILE_SHARE_READ;
|
||||
}
|
||||
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
|
||||
{
|
||||
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();
|
||||
response.FID = fileID;
|
||||
|
@ -198,10 +271,11 @@ namespace SMBLibrary.Server.SMB1
|
|||
response.NMPipeStatus.ICount = 255;
|
||||
response.NMPipeStatus.ReadMode = ReadMode.MessageMode;
|
||||
response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe;
|
||||
response.OpenResults.OpenResult = openResult;
|
||||
return response;
|
||||
}
|
||||
|
||||
private static OpenAndXResponseExtended CreateResponseExtendedForNamedPipe(ushort fileID)
|
||||
private static OpenAndXResponseExtended CreateResponseExtendedForNamedPipe(ushort fileID, OpenResult openResult)
|
||||
{
|
||||
OpenAndXResponseExtended response = new OpenAndXResponseExtended();
|
||||
response.FID = fileID;
|
||||
|
@ -210,12 +284,14 @@ namespace SMBLibrary.Server.SMB1
|
|||
response.NMPipeStatus.ICount = 255;
|
||||
response.NMPipeStatus.ReadMode = ReadMode.MessageMode;
|
||||
response.NMPipeStatus.NamedPipeType = NamedPipeType.MessageNodePipe;
|
||||
response.OpenResults.OpenResult = openResult;
|
||||
return response;
|
||||
}
|
||||
|
||||
private static OpenAndXResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult)
|
||||
{
|
||||
OpenAndXResponse response = new OpenAndXResponse();
|
||||
response.FID = fileID;
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
response.FileAttrs = SMBFileAttributes.Directory;
|
||||
|
@ -224,7 +300,6 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
response.FileAttrs = SMBFileAttributes.Normal;
|
||||
}
|
||||
response.FID = fileID;
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
||||
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)
|
||||
{
|
||||
OpenAndXResponseExtended response = new OpenAndXResponseExtended();
|
||||
response.FID = fileID;
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
response.FileAttrs = SMBFileAttributes.Directory;
|
||||
|
@ -244,7 +320,6 @@ namespace SMBLibrary.Server.SMB1
|
|||
{
|
||||
response.FileAttrs = SMBFileAttributes.Normal;
|
||||
}
|
||||
response.FID = fileID;
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
||||
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
|
||||
|
|
Loading…
Add table
Reference in a new issue