Server: Pass GetSecurityInformation and SetSecurityInformation requests to the underlying object store

This commit is contained in:
Tal Aloni 2017-09-25 23:51:29 +03:00
parent 204c912074
commit a17d827076
3 changed files with 127 additions and 4 deletions

View file

@ -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<SMB1Command> GetNTTransactResponse(byte[] responseSetup, byte[] responseParameters, byte[] responseData, int maxBufferSize)
{
List<SMB1Command> result = new List<SMB1Command>();

View file

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

View file

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