mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-05-15 17:06:59 +02:00
API improvement: FileSystemShare: Added OnAccessRequest event that allows the subscriber to manage read / write permissions
This commit is contained in:
parent
f9ad9f9b5e
commit
fd26380dab
16 changed files with 248 additions and 81 deletions
|
@ -20,10 +20,10 @@ namespace SMBLibrary.Server
|
||||||
public const int BytesPerSector = 512;
|
public const int BytesPerSector = 512;
|
||||||
public const int ClusterSize = 4096;
|
public const int ClusterSize = 4096;
|
||||||
|
|
||||||
public static NTStatus CreateFile(out FileSystemEntry entry, FileSystemShare share, string userName, string path, CreateDisposition createDisposition, CreateOptions createOptions, AccessMask desiredAccess, ConnectionState state)
|
public static NTStatus CreateFile(out FileSystemEntry entry, IFileSystem fileSystem, string path, AccessMask desiredAccess, CreateDisposition createDisposition, CreateOptions createOptions, ConnectionState state)
|
||||||
{
|
{
|
||||||
bool hasWriteAccess = share.HasWriteAccess(userName);
|
FileAccess createAccess = ToCreateFileAccess(desiredAccess, createDisposition);
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
bool requestedWriteAccess = (createAccess & FileAccess.Write) > 0;
|
||||||
|
|
||||||
bool forceDirectory = (createOptions & CreateOptions.FILE_DIRECTORY_FILE) > 0;
|
bool forceDirectory = (createOptions & CreateOptions.FILE_DIRECTORY_FILE) > 0;
|
||||||
bool forceFile = (createOptions & CreateOptions.FILE_NON_DIRECTORY_FILE) > 0;
|
bool forceFile = (createOptions & CreateOptions.FILE_NON_DIRECTORY_FILE) > 0;
|
||||||
|
@ -82,7 +82,7 @@ namespace SMBLibrary.Server
|
||||||
return NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
return NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasWriteAccess)
|
if (!requestedWriteAccess)
|
||||||
{
|
{
|
||||||
return NTStatus.STATUS_ACCESS_DENIED;
|
return NTStatus.STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ namespace SMBLibrary.Server
|
||||||
return NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
return NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasWriteAccess)
|
if (!requestedWriteAccess)
|
||||||
{
|
{
|
||||||
return NTStatus.STATUS_ACCESS_DENIED;
|
return NTStatus.STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ namespace SMBLibrary.Server
|
||||||
createDisposition == CreateDisposition.FILE_OVERWRITE_IF ||
|
createDisposition == CreateDisposition.FILE_OVERWRITE_IF ||
|
||||||
createDisposition == CreateDisposition.FILE_SUPERSEDE)
|
createDisposition == CreateDisposition.FILE_SUPERSEDE)
|
||||||
{
|
{
|
||||||
if (!hasWriteAccess)
|
if (!requestedWriteAccess)
|
||||||
{
|
{
|
||||||
return NTStatus.STATUS_ACCESS_DENIED;
|
return NTStatus.STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
@ -208,12 +208,6 @@ namespace SMBLibrary.Server
|
||||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAccess fileAccess = ToFileAccess(desiredAccess.File);
|
|
||||||
if (!hasWriteAccess && (fileAccess == FileAccess.Write || fileAccess == FileAccess.ReadWrite))
|
|
||||||
{
|
|
||||||
return NTStatus.STATUS_ACCESS_DENIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,6 +389,48 @@ namespace SMBLibrary.Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FileAccess ToCreateFileAccess(AccessMask desiredAccess, CreateDisposition createDisposition)
|
||||||
|
{
|
||||||
|
FileAccess result = 0;
|
||||||
|
|
||||||
|
if ((desiredAccess.File & FileAccessMask.FILE_READ_DATA) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.FILE_READ_EA) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.FILE_READ_ATTRIBUTES) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.MAXIMUM_ALLOWED) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.GENERIC_ALL) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.GENERIC_READ) > 0)
|
||||||
|
{
|
||||||
|
result |= FileAccess.Read;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((desiredAccess.File & FileAccessMask.FILE_WRITE_DATA) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.FILE_APPEND_DATA) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.FILE_WRITE_EA) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.FILE_WRITE_ATTRIBUTES) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.DELETE) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.WRITE_DAC) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.WRITE_OWNER) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.MAXIMUM_ALLOWED) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.GENERIC_ALL) > 0 ||
|
||||||
|
(desiredAccess.File & FileAccessMask.GENERIC_WRITE) > 0)
|
||||||
|
{
|
||||||
|
result |= FileAccess.Write;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((desiredAccess.Directory & DirectoryAccessMask.FILE_DELETE_CHILD) > 0)
|
||||||
|
{
|
||||||
|
result |= FileAccess.Write;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createDisposition == CreateDisposition.FILE_CREATE ||
|
||||||
|
createDisposition == CreateDisposition.FILE_SUPERSEDE)
|
||||||
|
{
|
||||||
|
result |= FileAccess.Write;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static FileAccess ToFileAccess(FileAccessMask desiredAccess)
|
public static FileAccess ToFileAccess(FileAccessMask desiredAccess)
|
||||||
{
|
{
|
||||||
FileAccess result = 0;
|
FileAccess result = 0;
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
internal static SMB1Command GetCreateDirectoryResponse(SMB1Header header, CreateDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
internal static SMB1Command GetCreateDirectoryResponse(SMB1Header header, CreateDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
SMB1Session session = state.GetSession(header.UID);
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
if (!share.HasWriteAccess(session.UserName))
|
if (!share.HasWriteAccess(session.UserName, request.DirectoryName, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
||||||
|
@ -48,7 +48,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
SMB1Session session = state.GetSession(header.UID);
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
if (!share.HasWriteAccess(session.UserName))
|
if (!share.HasWriteAccess(session.UserName, request.DirectoryName, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
||||||
|
@ -103,7 +103,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
|
internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
SMB1Session session = state.GetSession(header.UID);
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
if (!share.HasWriteAccess(session.UserName))
|
if (!share.HasWriteAccess(session.UserName, request.FileName, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
||||||
|
@ -146,7 +146,12 @@ namespace SMBLibrary.Server.SMB1
|
||||||
internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
|
internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
SMB1Session session = state.GetSession(header.UID);
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
if (!share.HasWriteAccess(session.UserName))
|
if (!share.HasWriteAccess(session.UserName, request.OldFileName, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||||
|
}
|
||||||
|
if (!share.HasWriteAccess(session.UserName, request.NewFileName, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
||||||
|
@ -210,7 +215,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, FileSystemShare share, SMB1ConnectionState state)
|
internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
SMB1Session session = state.GetSession(header.UID);
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
if (!share.HasWriteAccess(session.UserName))
|
if (!share.HasWriteAccess(session.UserName, request.FileName, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
||||||
|
@ -259,7 +264,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!share.HasWriteAccess(session.UserName))
|
if (!share.HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
||||||
|
|
|
@ -48,9 +48,15 @@ namespace SMBLibrary.Server.SMB1
|
||||||
else // FileSystemShare
|
else // FileSystemShare
|
||||||
{
|
{
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||||
string userName = session.UserName;
|
FileAccess createAccess = NTFileSystemHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition);
|
||||||
|
if (!fileSystemShare.HasAccess(session.UserName, path, createAccess, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return new ErrorResponse(request.CommandName);
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemEntry entry;
|
FileSystemEntry entry;
|
||||||
NTStatus createStatus = NTFileSystemHelper.CreateFile(out entry, fileSystemShare, userName, path, request.CreateDisposition, request.CreateOptions, request.DesiredAccess, state);
|
NTStatus createStatus = NTFileSystemHelper.CreateFile(out entry, fileSystemShare.FileSystem, path, request.DesiredAccess, request.CreateDisposition, request.CreateOptions, state);
|
||||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
header.Status = createStatus;
|
header.Status = createStatus;
|
||||||
|
|
|
@ -48,20 +48,19 @@ namespace SMBLibrary.Server.SMB1
|
||||||
else // FileSystemShare
|
else // FileSystemShare
|
||||||
{
|
{
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||||
string userName = session.UserName;
|
FileAccess fileAccess = ToFileAccess(request.AccessMode.AccessMode);
|
||||||
bool hasWriteAccess = fileSystemShare.HasWriteAccess(userName);
|
if (!fileSystemShare.HasAccess(session.UserName, path, fileAccess, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return new ErrorResponse(request.CommandName);
|
||||||
|
}
|
||||||
|
|
||||||
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
||||||
|
|
||||||
OpenResult openResult;
|
OpenResult openResult;
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
FileSystemEntry entry = fileSystem.GetEntry(path);
|
||||||
if (entry != null)
|
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)
|
if (request.OpenMode.FileExistsOpts == FileExistsOpts.ReturnError)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||||
|
@ -121,7 +120,6 @@ namespace SMBLibrary.Server.SMB1
|
||||||
openResult = OpenResult.NotExistedAndWasCreated;
|
openResult = OpenResult.NotExistedAndWasCreated;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAccess fileAccess = ToFileAccess(request.AccessMode.AccessMode);
|
|
||||||
FileShare fileShare = ToFileShare(request.AccessMode.SharingMode);
|
FileShare fileShare = ToFileShare(request.AccessMode.SharingMode);
|
||||||
Stream stream = null;
|
Stream stream = null;
|
||||||
if (!entry.IsDirectory)
|
if (!entry.IsDirectory)
|
||||||
|
|
|
@ -26,6 +26,16 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (share is FileSystemShare)
|
||||||
|
{
|
||||||
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return new ErrorResponse(request.CommandName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
byte[] data;
|
byte[] data;
|
||||||
header.Status = NTFileSystemHelper.ReadFile(out data, openFile, request.ReadOffsetInBytes, request.CountOfBytesToRead, state);
|
header.Status = NTFileSystemHelper.ReadFile(out data, openFile, request.ReadOffsetInBytes, request.CountOfBytesToRead, state);
|
||||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
|
@ -48,6 +58,16 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (share is FileSystemShare)
|
||||||
|
{
|
||||||
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return new ErrorResponse(request.CommandName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint maxCount = request.MaxCount;
|
uint maxCount = request.MaxCount;
|
||||||
if ((share is FileSystemShare) && state.LargeRead)
|
if ((share is FileSystemShare) && state.LargeRead)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +99,16 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (share is FileSystemShare)
|
||||||
|
{
|
||||||
|
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return new ErrorResponse(request.CommandName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int numberOfBytesWritten;
|
int numberOfBytesWritten;
|
||||||
header.Status = NTFileSystemHelper.WriteFile(out numberOfBytesWritten, openFile, request.WriteOffsetInBytes, request.Data, state);
|
header.Status = NTFileSystemHelper.WriteFile(out numberOfBytesWritten, openFile, request.WriteOffsetInBytes, request.Data, state);
|
||||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
|
@ -99,6 +129,16 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (share is FileSystemShare)
|
||||||
|
{
|
||||||
|
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return new ErrorResponse(request.CommandName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int numberOfBytesWritten;
|
int numberOfBytesWritten;
|
||||||
header.Status = NTFileSystemHelper.WriteFile(out numberOfBytesWritten, openFile, (long)request.Offset, request.Data, state);
|
header.Status = NTFileSystemHelper.WriteFile(out numberOfBytesWritten, openFile, (long)request.Offset, request.Data, state);
|
||||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
|
|
|
@ -116,6 +116,13 @@ namespace SMBLibrary.Server.SMB1
|
||||||
|
|
||||||
internal static Transaction2QueryFSInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFSInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
|
internal static Transaction2QueryFSInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFSInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
|
if (!share.HasReadAccess(session.UserName, @"\", state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();
|
Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();
|
||||||
QueryFSInformation queryFSInformation;
|
QueryFSInformation queryFSInformation;
|
||||||
NTStatus queryStatus = SMB1FileSystemHelper.GetFileSystemInformation(out queryFSInformation, subcommand.InformationLevel, share.FileSystem);
|
NTStatus queryStatus = SMB1FileSystemHelper.GetFileSystemInformation(out queryFSInformation, subcommand.InformationLevel, share.FileSystem);
|
||||||
|
@ -131,8 +138,15 @@ namespace SMBLibrary.Server.SMB1
|
||||||
|
|
||||||
internal static Transaction2QueryPathInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryPathInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
|
internal static Transaction2QueryPathInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryPathInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
string path = subcommand.FileName;
|
string path = subcommand.FileName;
|
||||||
|
if (!share.HasReadAccess(session.UserName, path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFileSystem fileSystem = share.FileSystem;
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
FileSystemEntry entry = fileSystem.GetEntry(path);
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
{
|
{
|
||||||
|
@ -165,6 +179,12 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!share.HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(openFile.Path);
|
FileSystemEntry entry = fileSystem.GetEntry(openFile.Path);
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
|
@ -195,6 +215,12 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!share.HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
SetInformation information;
|
SetInformation information;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -211,12 +237,6 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!share.HasWriteAccess(session.UserName))
|
|
||||||
{
|
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTStatus status = SMB1FileSystemHelper.SetFileInformation(share.FileSystem, openFile, information, state);
|
NTStatus status = SMB1FileSystemHelper.SetFileInformation(share.FileSystem, openFile, information, state);
|
||||||
if (status != NTStatus.STATUS_SUCCESS)
|
if (status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
|
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((FileSystemShare)share).HasReadAccess(session.UserName))
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, @"\", state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
|
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
|
||||||
|
|
|
@ -42,9 +42,14 @@ namespace SMBLibrary.Server.SMB2
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||||
|
FileAccess createAccess = NTFileSystemHelper.ToCreateFileAccess(request.DesiredAccess, request.CreateDisposition);
|
||||||
|
if (!fileSystemShare.HasAccess(session.UserName, path, createAccess, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemEntry entry;
|
FileSystemEntry entry;
|
||||||
NTStatus createStatus = NTFileSystemHelper.CreateFile(out entry, (FileSystemShare)share, session.UserName, path, request.CreateDisposition, request.CreateOptions, request.DesiredAccess, state);
|
NTStatus createStatus = NTFileSystemHelper.CreateFile(out entry, fileSystemShare.FileSystem, path, request.DesiredAccess, request.CreateDisposition, request.CreateOptions, state);
|
||||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, createStatus);
|
return new ErrorResponse(request.CommandName, createStatus);
|
||||||
|
|
|
@ -28,6 +28,11 @@ namespace SMBLibrary.Server.SMB2
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||||
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,10 @@ namespace SMBLibrary.Server.SMB2
|
||||||
}
|
}
|
||||||
else // FileSystemShare
|
else // FileSystemShare
|
||||||
{
|
{
|
||||||
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
|
}
|
||||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(openFile.Path);
|
FileSystemEntry entry = fileSystem.GetEntry(openFile.Path);
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
|
@ -56,6 +60,10 @@ namespace SMBLibrary.Server.SMB2
|
||||||
{
|
{
|
||||||
if (share is FileSystemShare)
|
if (share is FileSystemShare)
|
||||||
{
|
{
|
||||||
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, @"\", state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
|
}
|
||||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
||||||
FileSystemInformation fileSystemInformation;
|
FileSystemInformation fileSystemInformation;
|
||||||
NTStatus queryStatus = NTFileSystemHelper.GetFileSystemInformation(out fileSystemInformation, request.FileSystemInformationClass, fileSystem);
|
NTStatus queryStatus = NTFileSystemHelper.GetFileSystemInformation(out fileSystemInformation, request.FileSystemInformationClass, fileSystem);
|
||||||
|
|
|
@ -28,10 +28,11 @@ namespace SMBLibrary.Server.SMB2
|
||||||
if (share is FileSystemShare)
|
if (share is FileSystemShare)
|
||||||
{
|
{
|
||||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
||||||
if (!((FileSystemShare)share).HasWriteAccess(session.UserName))
|
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInformation information;
|
FileInformation information;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -50,6 +51,15 @@ namespace SMBLibrary.Server.SMB2
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (information is FileRenameInformationType2)
|
||||||
|
{
|
||||||
|
string newFileName = ((FileRenameInformationType2)information).FileName;
|
||||||
|
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, newFileName, state.ClientEndPoint))
|
||||||
|
{
|
||||||
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NTStatus status = NTFileSystemHelper.SetFileInformation(fileSystem, openFile, information, state);
|
NTStatus status = NTFileSystemHelper.SetFileInformation(fileSystem, openFile, information, state);
|
||||||
if (status != NTStatus.STATUS_SUCCESS)
|
if (status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace SMBLibrary.Server.SMB2
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_OBJECT_PATH_NOT_FOUND);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_OBJECT_PATH_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((FileSystemShare)share).HasReadAccess(session.UserName))
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, @"\", state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,12 +218,6 @@ namespace SMBLibrary.Server
|
||||||
}
|
}
|
||||||
else if (command is WriteRequest)
|
else if (command is WriteRequest)
|
||||||
{
|
{
|
||||||
string userName = session.UserName;
|
|
||||||
if (share is FileSystemShare && !((FileSystemShare)share).HasWriteAccess(userName))
|
|
||||||
{
|
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
||||||
return new ErrorResponse(command.CommandName);
|
|
||||||
}
|
|
||||||
WriteRequest request = (WriteRequest)command;
|
WriteRequest request = (WriteRequest)command;
|
||||||
return ReadWriteResponseHelper.GetWriteResponse(header, request, share, state);
|
return ReadWriteResponseHelper.GetWriteResponse(header, request, share, state);
|
||||||
}
|
}
|
||||||
|
@ -272,12 +266,6 @@ namespace SMBLibrary.Server
|
||||||
}
|
}
|
||||||
else if (command is WriteAndXRequest)
|
else if (command is WriteAndXRequest)
|
||||||
{
|
{
|
||||||
string userName = session.UserName;
|
|
||||||
if (share is FileSystemShare && !((FileSystemShare)share).HasWriteAccess(userName))
|
|
||||||
{
|
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
||||||
return new ErrorResponse(command.CommandName);
|
|
||||||
}
|
|
||||||
WriteAndXRequest request = (WriteAndXRequest)command;
|
WriteAndXRequest request = (WriteAndXRequest)command;
|
||||||
return ReadWriteResponseHelper.GetWriteResponse(header, request, share, state);
|
return ReadWriteResponseHelper.GetWriteResponse(header, request, share, state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,36 @@
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Utilities;
|
using Utilities;
|
||||||
|
|
||||||
namespace SMBLibrary.Server
|
namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
|
public class AccessRequestArgs : EventArgs
|
||||||
|
{
|
||||||
|
public string UserName;
|
||||||
|
public string Path;
|
||||||
|
public FileAccess RequestedAccess;
|
||||||
|
public IPEndPoint ClientEndPoint;
|
||||||
|
public bool Allow = true;
|
||||||
|
|
||||||
|
public AccessRequestArgs(string userName, string path, FileAccess requestedAccess, IPEndPoint clientEndPoint)
|
||||||
|
{
|
||||||
|
UserName = userName;
|
||||||
|
Path = path;
|
||||||
|
RequestedAccess = requestedAccess;
|
||||||
|
ClientEndPoint = clientEndPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class FileSystemShare : ISMBShare
|
public class FileSystemShare : ISMBShare
|
||||||
{
|
{
|
||||||
private string m_name;
|
private string m_name;
|
||||||
public IFileSystem m_fileSystem;
|
public IFileSystem m_fileSystem;
|
||||||
public List<string> ReadAccess;
|
|
||||||
public List<string> WriteAccess;
|
public event EventHandler<AccessRequestArgs> OnAccessRequest;
|
||||||
|
|
||||||
public FileSystemShare(string shareName, IFileSystem fileSystem)
|
public FileSystemShare(string shareName, IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
|
@ -24,31 +43,27 @@ namespace SMBLibrary.Server
|
||||||
m_fileSystem = fileSystem;
|
m_fileSystem = fileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasReadAccess(string userName)
|
public bool HasReadAccess(string userName, string path, IPEndPoint clientEndPoint)
|
||||||
{
|
{
|
||||||
return Contains(ReadAccess, userName);
|
return HasAccess(userName, path, FileAccess.Read, clientEndPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasWriteAccess(string userName)
|
public bool HasWriteAccess(string userName, string path, IPEndPoint clientEndPoint)
|
||||||
{
|
{
|
||||||
return Contains(WriteAccess, userName);
|
return HasAccess(userName, path, FileAccess.Write, clientEndPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Contains(List<string> list, string value)
|
public bool HasAccess(string userName, string path, FileAccess requestedAccess, IPEndPoint clientEndPoint)
|
||||||
{
|
{
|
||||||
return (IndexOf(list, value) >= 0);
|
// To be thread-safe we must capture the delegate reference first
|
||||||
}
|
EventHandler<AccessRequestArgs> handler = OnAccessRequest;
|
||||||
|
if (handler != null)
|
||||||
public static int IndexOf(List<string> list, string value)
|
|
||||||
{
|
|
||||||
for (int index = 0; index < list.Count; index++)
|
|
||||||
{
|
{
|
||||||
if (string.Equals(list[index], value, StringComparison.InvariantCultureIgnoreCase))
|
AccessRequestArgs args = new AccessRequestArgs(userName, path, requestedAccess, clientEndPoint);
|
||||||
{
|
handler(this, args);
|
||||||
return index;
|
return args.Allow;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return -1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
|
|
|
@ -13,11 +13,9 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
public class ShareCollection : List<FileSystemShare>
|
public class ShareCollection : List<FileSystemShare>
|
||||||
{
|
{
|
||||||
public void Add(string shareName, List<string> readAccess, List<string> writeAccess, IFileSystem fileSystem)
|
public void Add(string shareName, IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
FileSystemShare share = new FileSystemShare(shareName, fileSystem);
|
FileSystemShare share = new FileSystemShare(shareName, fileSystem);
|
||||||
share.ReadAccess = readAccess;
|
|
||||||
share.WriteAccess = writeAccess;
|
|
||||||
this.Add(share);
|
this.Add(share);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,23 @@ namespace SMBServer
|
||||||
List<string> readAccess = ReadAccessList(readAccessNode, allUsers);
|
List<string> readAccess = ReadAccessList(readAccessNode, allUsers);
|
||||||
XmlNode writeAccessNode = shareNode.SelectSingleNode("WriteAccess");
|
XmlNode writeAccessNode = shareNode.SelectSingleNode("WriteAccess");
|
||||||
List<string> writeAccess = ReadAccessList(writeAccessNode, allUsers);
|
List<string> writeAccess = ReadAccessList(writeAccessNode, allUsers);
|
||||||
shares.Add(shareName, readAccess, writeAccess, new DirectoryFileSystem(sharePath));
|
FileSystemShare share = new FileSystemShare(shareName, new DirectoryFileSystem(sharePath));
|
||||||
|
share.OnAccessRequest += delegate(object sender, AccessRequestArgs args)
|
||||||
|
{
|
||||||
|
if (args.RequestedAccess == FileAccess.Read)
|
||||||
|
{
|
||||||
|
args.Allow = Contains(readAccess, args.UserName);
|
||||||
|
}
|
||||||
|
else if (args.RequestedAccess == FileAccess.Write)
|
||||||
|
{
|
||||||
|
args.Allow = Contains(writeAccess, args.UserName);
|
||||||
|
}
|
||||||
|
else // FileAccess.ReadWrite
|
||||||
|
{
|
||||||
|
args.Allow = Contains(readAccess, args.UserName) && Contains(writeAccess, args.UserName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
shares.Add(share);
|
||||||
}
|
}
|
||||||
return shares;
|
return shares;
|
||||||
}
|
}
|
||||||
|
@ -207,13 +223,6 @@ namespace SMBServer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static XmlDocument GetXmlDocument(string path)
|
|
||||||
{
|
|
||||||
XmlDocument doc = new XmlDocument();
|
|
||||||
doc.Load(path);
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Server_OnLogEntry(object sender, LogEntry entry)
|
private void Server_OnLogEntry(object sender, LogEntry entry)
|
||||||
{
|
{
|
||||||
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ");
|
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ");
|
||||||
|
@ -236,5 +245,29 @@ namespace SMBServer
|
||||||
chkSMB1.Checked = true;
|
chkSMB1.Checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static XmlDocument GetXmlDocument(string path)
|
||||||
|
{
|
||||||
|
XmlDocument doc = new XmlDocument();
|
||||||
|
doc.Load(path);
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Contains(List<string> list, string value)
|
||||||
|
{
|
||||||
|
return (IndexOf(list, value) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int IndexOf(List<string> list, string value)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < list.Count; index++)
|
||||||
|
{
|
||||||
|
if (string.Equals(list[index], value, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue