Browse Source

Server: Pass SetFileSystemInformation requests to the underlying object store

Tal Aloni 7 years ago
parent
commit
0f754ee55c

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

+ 1 - 1
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)
             {

+ 39 - 0
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;