diff --git a/SMBLibrary/Server/SMB1/NTTransactHelper.cs b/SMBLibrary/Server/SMB1/NTTransactHelper.cs index 99d0a1a..84be763 100644 --- a/SMBLibrary/Server/SMB1/NTTransactHelper.cs +++ b/SMBLibrary/Server/SMB1/NTTransactHelper.cs @@ -98,7 +98,7 @@ namespace SMBLibrary.Server.SMB1 } else if (subcommand is NTTransactSetSecurityDescriptorRequest) { - header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; + subcommandResponse = GetSubcommandResponse(header, (NTTransactSetSecurityDescriptorRequest)subcommand, share, state); } else if (subcommand is NTTransactNotifyChangeRequest) { @@ -110,7 +110,7 @@ namespace SMBLibrary.Server.SMB1 } else if (subcommand is NTTransactQuerySecurityDescriptorRequest) { - header.Status = NTStatus.STATUS_NOT_IMPLEMENTED; + subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactQuerySecurityDescriptorRequest)subcommand, share, state); } else { @@ -164,6 +164,64 @@ namespace SMBLibrary.Server.SMB1 return response; } + private static NTTransactSetSecurityDescriptorResponse GetSubcommandResponse(SMB1Header header, NTTransactSetSecurityDescriptorRequest subcommand, ISMBShare share, SMB1ConnectionState state) + { + SMB1Session session = state.GetSession(header.UID); + OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); + if (openFile == null) + { + state.LogToServer(Severity.Verbose, "SetSecurityInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID); + header.Status = NTStatus.STATUS_INVALID_HANDLE; + return null; + } + + header.Status = share.FileStore.SetSecurityInformation(openFile.Handle, subcommand.SecurityInformation, subcommand.SecurityDescriptor); + if (header.Status != NTStatus.STATUS_SUCCESS) + { + state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SecurityInformation.ToString("X"), header.Status, subcommand.FID); + return null; + } + + state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInformation.ToString("X"), subcommand.FID); + NTTransactSetSecurityDescriptorResponse response = new NTTransactSetSecurityDescriptorResponse(); + return response; + } + + private static NTTransactQuerySecurityDescriptorResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactQuerySecurityDescriptorRequest subcommand, ISMBShare share, SMB1ConnectionState state) + { + SMB1Session session = state.GetSession(header.UID); + OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID); + if (openFile == null) + { + state.LogToServer(Severity.Verbose, "GetSecurityInformation failed. Invalid FID. (UID: {0}, TID: {1}, FID: {2})", header.UID, header.TID, subcommand.FID); + header.Status = NTStatus.STATUS_INVALID_HANDLE; + return null; + } + + int maxOutputLength = (int)maxDataCount; + SecurityDescriptor securityDescriptor; + header.Status = share.FileStore.GetSecurityInformation(out securityDescriptor, openFile.Handle, subcommand.SecurityInfoFields); + if (header.Status != NTStatus.STATUS_SUCCESS) + { + state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), header.Status, subcommand.FID); + return null; + } + + NTTransactQuerySecurityDescriptorResponse response = new NTTransactQuerySecurityDescriptorResponse(); + response.LengthNeeded = (uint)securityDescriptor.Length; + if (response.LengthNeeded <= maxDataCount) + { + state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), subcommand.FID); + response.SecurityDescriptor = securityDescriptor; + } + else + { + state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: STATUS_BUFFER_TOO_SMALL. (FID: {3})", share.Name, openFile.Path, subcommand.SecurityInfoFields.ToString("X"), subcommand.FID); + header.Status = NTStatus.STATUS_BUFFER_TOO_SMALL; + } + return response; + } + internal static List GetNTTransactResponse(byte[] responseSetup, byte[] responseParameters, byte[] responseData, int maxBufferSize) { List result = new List(); diff --git a/SMBLibrary/Server/SMB2/QueryInfoHelper.cs b/SMBLibrary/Server/SMB2/QueryInfoHelper.cs index 92e3fb3..7704764 100644 --- a/SMBLibrary/Server/SMB2/QueryInfoHelper.cs +++ b/SMBLibrary/Server/SMB2/QueryInfoHelper.cs @@ -72,6 +72,44 @@ namespace SMBLibrary.Server.SMB2 return response; } } + else if (request.InfoType == InfoType.Security) + { + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); + if (openFile == null) + { + state.LogToServer(Severity.Verbose, "GetSecurityInformation failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile); + return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); + } + + if (share is FileSystemShare) + { + if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path)) + { + state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); + return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED); + } + } + + SecurityDescriptor securityDescriptor; + NTStatus queryStatus = share.FileStore.GetSecurityInformation(out securityDescriptor, openFile.Handle, request.SecurityInformation); + if (queryStatus != NTStatus.STATUS_SUCCESS) + { + state.LogToServer(Severity.Verbose, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), queryStatus, request.FileId.Volatile); + return new ErrorResponse(request.CommandName, queryStatus); + } + + if (securityDescriptor.Length > request.OutputBufferLength) + { + state.LogToServer(Severity.Information, "GetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: STATUS_BUFFER_TOO_SMALL. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile); + byte[] errorData = LittleEndianConverter.GetBytes((uint)securityDescriptor.Length); + return new ErrorResponse(request.CommandName, NTStatus.STATUS_BUFFER_TOO_SMALL, errorData); + } + + state.LogToServer(Severity.Information, "GetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile); + QueryInfoResponse response = new QueryInfoResponse(); + response.SetSecurityInformation(securityDescriptor); + return response; + } return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED); } } diff --git a/SMBLibrary/Server/SMB2/SetInfoHelper.cs b/SMBLibrary/Server/SMB2/SetInfoHelper.cs index 46aeb3d..386134b 100644 --- a/SMBLibrary/Server/SMB2/SetInfoHelper.cs +++ b/SMBLibrary/Server/SMB2/SetInfoHelper.cs @@ -17,9 +17,10 @@ namespace SMBLibrary.Server.SMB2 internal static SMB2Command GetSetInfoResponse(SetInfoRequest request, ISMBShare share, SMB2ConnectionState state) { SMB2Session session = state.GetSession(request.Header.SessionID); - if (request.InfoType == InfoType.File) + OpenFileObject openFile = null; + if (request.InfoType == InfoType.File || request.InfoType == InfoType.Security) { - OpenFileObject openFile = session.GetOpenFileObject(request.FileId); + openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { state.LogToServer(Severity.Verbose, "SetFileInformation failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile); @@ -34,7 +35,10 @@ namespace SMBLibrary.Server.SMB2 return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED); } } + } + if (request.InfoType == InfoType.File) + { FileInformation information; try { @@ -93,6 +97,29 @@ namespace SMBLibrary.Server.SMB2 } return new SetInfoResponse(); } + else if (request.InfoType == InfoType.Security) + { + SecurityDescriptor securityDescriptor; + try + { + securityDescriptor = new SecurityDescriptor(request.Buffer, 0); + } + catch + { + state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' failed. NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path); + return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER); + } + + NTStatus status = share.FileStore.SetSecurityInformation(openFile, request.SecurityInformation, securityDescriptor); + if (status != NTStatus.STATUS_SUCCESS) + { + state.LogToServer(Severity.Verbose, "SetSecurityInformation on '{0}{1}' failed. Security information: 0x{2}, NTStatus: {3}. (FileId: {4})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), status, request.FileId.Volatile); + return new ErrorResponse(request.CommandName, status); + } + + state.LogToServer(Severity.Information, "SetSecurityInformation on '{0}{1}' succeeded. Security information: 0x{2}. (FileId: {3})", share.Name, openFile.Path, request.SecurityInformation.ToString("X"), request.FileId.Volatile); + return new SetInfoResponse(); + } return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED); } }