diff --git a/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs b/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs index f5f03f2..f376976 100644 --- a/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs +++ b/SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs @@ -174,6 +174,56 @@ namespace SMBLibrary.Server.SMB1 return response; } + internal static Transaction2SetFSInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2SetFSInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state) + { + SMB1Session session = state.GetSession(header.UID); + if (share is FileSystemShare) + { + if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, @"\")) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. User '{1}' was denied access.", share.Name, session.UserName); + header.Status = NTStatus.STATUS_ACCESS_DENIED; + return null; + } + } + + if (!subcommand.IsPassthroughInformationLevel) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Not a pass-through information level.", share.Name); + header.Status = NTStatus.STATUS_NOT_SUPPORTED; + return null; + } + + FileSystemInformation fileSystemInfo; + try + { + fileSystemInfo = FileSystemInformation.GetFileSystemInformation(subcommand.InformationBytes, 0, subcommand.FileSystemInformationClass); + } + catch (UnsupportedInformationLevelException) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, subcommand.FileSystemInformationClass); + header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL; + return null; + } + catch (Exception) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, subcommand.FileSystemInformationClass); + header.Status = NTStatus.STATUS_INVALID_PARAMETER; + return null; + } + + NTStatus status = share.FileStore.SetFileSystemInformation(fileSystemInfo); + if (status != NTStatus.STATUS_SUCCESS) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}.", share.Name, subcommand.FileSystemInformationClass, status); + header.Status = status; + return null; + } + + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' succeeded. Information class: {1}.", share.Name, subcommand.FileSystemInformationClass); + return new Transaction2SetFSInformationResponse(); + } + internal static Transaction2QueryPathInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryPathInformationRequest subcommand, ISMBShare share, SMB1ConnectionState state) { SMB1Session session = state.GetSession(header.UID); diff --git a/SMBLibrary/Server/SMB1/TransactionHelper.cs b/SMBLibrary/Server/SMB1/TransactionHelper.cs index 010ee46..695efcd 100644 --- a/SMBLibrary/Server/SMB1/TransactionHelper.cs +++ b/SMBLibrary/Server/SMB1/TransactionHelper.cs @@ -210,7 +210,7 @@ namespace SMBLibrary.Server.SMB1 } else if (subcommand is Transaction2SetFSInformationRequest) { - header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; + subcommandResponse = Transaction2SubcommandHelper.GetSubcommandResponse(header, (Transaction2SetFSInformationRequest)subcommand, share, state); } else if (subcommand is Transaction2QueryPathInformationRequest) { diff --git a/SMBLibrary/Server/SMB2/SetInfoHelper.cs b/SMBLibrary/Server/SMB2/SetInfoHelper.cs index 386134b..ec68419 100644 --- a/SMBLibrary/Server/SMB2/SetInfoHelper.cs +++ b/SMBLibrary/Server/SMB2/SetInfoHelper.cs @@ -36,6 +36,17 @@ namespace SMBLibrary.Server.SMB2 } } } + else if (request.InfoType == InfoType.FileSystem) + { + if (share is FileSystemShare) + { + if (!((FileSystemShare)share).HasWriteAccess(session.SecurityContext, @"\")) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. User '{1}' was denied access.", share.Name, session.UserName); + return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED); + } + } + } if (request.InfoType == InfoType.File) { @@ -97,6 +108,34 @@ namespace SMBLibrary.Server.SMB2 } return new SetInfoResponse(); } + else if (request.InfoType == InfoType.FileSystem) + { + FileSystemInformation fileSystemInformation; + try + { + fileSystemInformation = FileSystemInformation.GetFileSystemInformation(request.Buffer, 0, request.FileSystemInformationClass); + } + catch (UnsupportedInformationLevelException) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: STATUS_INVALID_INFO_CLASS.", share.Name, request.FileSystemInformationClass); + return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS); + } + catch (Exception) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, request.FileSystemInformationClass); + return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER); + } + + NTStatus status = share.FileStore.SetFileSystemInformation(fileSystemInformation); + if (status != NTStatus.STATUS_SUCCESS) + { + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}.", share.Name, request.FileSystemInformationClass, status); + return new ErrorResponse(request.CommandName, status); + } + + state.LogToServer(Severity.Verbose, "SetFileSystemInformation on '{0}' succeeded. Information class: {1}.", share.Name, request.FileSystemInformationClass); + return new SetInfoResponse(); + } else if (request.InfoType == InfoType.Security) { SecurityDescriptor securityDescriptor;