API improvement: FileSystemShare: Added OnAccessRequest event that allows the subscriber to manage read / write permissions

This commit is contained in:
Tal Aloni 2017-02-09 14:22:52 +02:00
parent f9ad9f9b5e
commit fd26380dab
16 changed files with 248 additions and 81 deletions

View file

@ -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;

View file

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

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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)
{ {

View file

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

View file

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

View file

@ -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;

View file

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

View file

@ -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)
{ {

View file

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

View file

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

View file

@ -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

View file

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

View file

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