Quellcode durchsuchen

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

Tal Aloni vor 7 Jahren
Ursprung
Commit
a17d827076

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

+ 38 - 0
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);
         }
     }

+ 29 - 2
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);
         }
     }