Sfoglia il codice sorgente

Added SMB1FileSystemHelper.SetFileInformation helper method

Tal Aloni 8 anni fa
parent
commit
7791f27276

+ 9 - 4
SMBLibrary/SMB1/Transaction2Subcommands/Transaction2SetFileInformationRequest.cs

@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
+/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  * 
  * You can redistribute this program and/or modify it under the terms of
  * the GNU Lesser Public License as published by the Free Software Foundation,
@@ -22,7 +22,7 @@ namespace SMBLibrary.SMB1
         public SetInformationLevel InformationLevel;
         public ushort Reserved;
         // Data:
-        public SetInformation SetInfo;
+        public byte[] InformationBytes;
 
         public Transaction2SetFileInformationRequest() : base()
         {
@@ -34,7 +34,7 @@ namespace SMBLibrary.SMB1
             InformationLevel = (SetInformationLevel)LittleEndianConverter.ToUInt16(parameters, 2);
             Reserved = LittleEndianConverter.ToUInt16(parameters, 4);
 
-            SetInfo = SetInformation.GetSetInformation(data, InformationLevel);
+            InformationBytes = data;
         }
 
         public override byte[] GetSetup()
@@ -53,7 +53,12 @@ namespace SMBLibrary.SMB1
 
         public override byte[] GetData(bool isUnicode)
         {
-            return SetInfo.GetBytes();
+            return InformationBytes;
+        }
+
+        public void SetInformation(SetInformation information)
+        {
+            InformationBytes = information.GetBytes();
         }
 
         public override Transaction2SubcommandName SubcommandName

+ 1 - 0
SMBLibrary/SMBLibrary.csproj

@@ -138,6 +138,7 @@
     <Compile Include="Server\SMB1\SMB1FileSystemHelper.Find.cs" />
     <Compile Include="Server\SMB1\SMB1FileSystemHelper.Query.cs" />
     <Compile Include="Server\SMB1\SMB1FileSystemHelper.QueryFileSystem.cs" />
+    <Compile Include="Server\SMB1\SMB1FileSystemHelper.Set.cs" />
     <Compile Include="Server\SMB1\Transaction2SubcommandHelper.cs" />
     <Compile Include="Server\SMB1\TransactionHelper.cs" />
     <Compile Include="Server\SMB1\TransactionSubcommandHelper.cs" />

+ 171 - 0
SMBLibrary/Server/SMB1/SMB1FileSystemHelper.Set.cs

@@ -0,0 +1,171 @@
+/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
+ * 
+ * You can redistribute this program and/or modify it under the terms of
+ * the GNU Lesser Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using SMBLibrary.SMB1;
+using Utilities;
+
+namespace SMBLibrary.Server.SMB1
+{
+    public partial class SMB1FileSystemHelper
+    {
+        public static NTStatus SetFileInformation(IFileSystem fileSystem, OpenFileObject openFile, SetInformation information, ConnectionState state)
+        {
+            if (information is SetInfoStandard)
+            {
+                return NTStatus.STATUS_SUCCESS;
+            }
+            else if (information is SetExtendedAttributes)
+            {
+                return NTStatus.STATUS_NOT_IMPLEMENTED;
+            }
+            else if (information is SetFileBasicInfo)
+            {
+                SetFileBasicInfo basicInfo = (SetFileBasicInfo)information;
+                bool isHidden = (basicInfo.ExtFileAttributes & ExtendedFileAttributes.Hidden) > 0;
+                bool isReadonly = (basicInfo.ExtFileAttributes & ExtendedFileAttributes.Readonly) > 0;
+                bool isArchived = (basicInfo.ExtFileAttributes & ExtendedFileAttributes.Archive) > 0;
+                try
+                {
+                    fileSystem.SetAttributes(openFile.Path, isHidden, isReadonly, isArchived);
+                }
+                catch (UnauthorizedAccessException)
+                {
+                    state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file attributes on '{0}'. Access Denied.", openFile.Path);
+                    return NTStatus.STATUS_ACCESS_DENIED;
+                }
+
+                try
+                {
+                    fileSystem.SetDates(openFile.Path, basicInfo.CreationTime, basicInfo.LastWriteTime, basicInfo.LastAccessTime);
+                }
+                catch (IOException ex)
+                {
+                    ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
+                    if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
+                    {
+                        // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid
+                        state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. Sharing Violation.", openFile.Path);
+                        return NTStatus.STATUS_SHARING_VIOLATION;
+                    }
+                    else
+                    {
+                        state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. Data Error.", openFile.Path);
+                        return NTStatus.STATUS_DATA_ERROR;
+                    }
+                }
+                catch (UnauthorizedAccessException)
+                {
+                    state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. Access Denied.", openFile.Path);
+                    return NTStatus.STATUS_ACCESS_DENIED;
+                }
+                return NTStatus.STATUS_SUCCESS;
+            }
+            else if (information is SetFileDispositionInfo)
+            {
+                if (((SetFileDispositionInfo)information).DeletePending)
+                {
+                    // We're supposed to delete the file on close, but it's too late to report errors at this late stage
+                    if (openFile.Stream != null)
+                    {
+                        openFile.Stream.Close();
+                    }
+
+                    try
+                    {
+                        state.LogToServer(Severity.Information, "SetFileInformation: Deleting file '{0}'", openFile.Path);
+                        fileSystem.Delete(openFile.Path);
+                    }
+                    catch (IOException ex)
+                    {
+                        ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
+                        if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
+                        {
+                            state.LogToServer(Severity.Information, "SetFileInformation: Error deleting '{0}'. Sharing Violation.", openFile.Path);
+                            return NTStatus.STATUS_SHARING_VIOLATION;
+                        }
+                        else
+                        {
+                            state.LogToServer(Severity.Information, "SetFileInformation: Error deleting '{0}'. Data Error.", openFile.Path);
+                            return NTStatus.STATUS_DATA_ERROR;
+                        }
+                    }
+                    catch (UnauthorizedAccessException)
+                    {
+                        state.LogToServer(Severity.Information, "SetFileInformation: Error deleting '{0}', Access Denied.", openFile.Path);
+                        return NTStatus.STATUS_ACCESS_DENIED;
+                    }
+                }
+                return NTStatus.STATUS_SUCCESS;
+            }
+            else if (information is SetFileAllocationInfo)
+            {
+                // This information level is used to set the file length in bytes.
+                // Note: the input will NOT be a multiple of the cluster size / bytes per sector.
+                ulong allocationSize = ((SetFileAllocationInfo)information).AllocationSize;
+                try
+                {
+                    openFile.Stream.SetLength((long)allocationSize);
+                }
+                catch (IOException ex)
+                {
+                    ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
+                    if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
+                    {
+                        state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. Sharing Violation.", openFile.Path);
+                        return NTStatus.STATUS_SHARING_VIOLATION;
+                    }
+                    else
+                    {
+                        state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. Data Error.", openFile.Path);
+                        return NTStatus.STATUS_DATA_ERROR;
+                    }
+                }
+                catch (UnauthorizedAccessException)
+                {
+                    state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. Access Denied.", openFile.Path);
+                    return NTStatus.STATUS_ACCESS_DENIED;
+                }
+                return NTStatus.STATUS_SUCCESS;
+            }
+            else if (information is SetFileEndOfFileInfo)
+            {
+                ulong endOfFile = ((SetFileEndOfFileInfo)information).EndOfFile;
+                try
+                {
+                    openFile.Stream.SetLength((long)endOfFile);
+                }
+                catch (IOException ex)
+                {
+                    ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
+                    if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
+                    {
+                        state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. Sharing Violation.", openFile.Path);
+                        return NTStatus.STATUS_SHARING_VIOLATION;
+                    }
+                    else
+                    {
+                        state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. Data Error.", openFile.Path);
+                        return NTStatus.STATUS_DATA_ERROR;
+                    }
+                }
+                catch (UnauthorizedAccessException)
+                {
+                    state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. Access Denied.", openFile.Path);
+                    return NTStatus.STATUS_ACCESS_DENIED;
+                }
+                return NTStatus.STATUS_SUCCESS;
+            }
+            else
+            {
+                return NTStatus.STATUS_NOT_IMPLEMENTED;
+            }
+        }
+    }
+}

+ 27 - 132
SMBLibrary/Server/SMB1/Transaction2SubcommandHelper.cs

@@ -192,142 +192,37 @@ namespace SMBLibrary.Server.SMB1
                 return null;
             }
 
-            Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse();
-            switch (subcommand.InformationLevel)
+            SetInformation information;
+            try
             {
-                case SetInformationLevel.SMB_INFO_STANDARD:
-                {
-                    return response;
-                }
-                case SetInformationLevel.SMB_INFO_SET_EAS:
-                {
-                    throw new NotImplementedException();
-                }
-                case SetInformationLevel.SMB_SET_FILE_BASIC_INFO:
-                {
-                    if (!share.HasWriteAccess(session.UserName))
-                    {
-                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
-                        return null;
-                    }
-
-                    SetFileBasicInfo info = (SetFileBasicInfo)subcommand.SetInfo;
-                    bool isHidden = (info.ExtFileAttributes & ExtendedFileAttributes.Hidden) > 0;
-                    bool isReadonly = (info.ExtFileAttributes & ExtendedFileAttributes.Readonly) > 0;
-                    bool isArchived = (info.ExtFileAttributes & ExtendedFileAttributes.Archive) > 0;
-                    try
-                    {
-                        share.FileSystem.SetAttributes(openFile.Path, isHidden, isReadonly, isArchived);
-                    }
-                    catch (UnauthorizedAccessException)
-                    {
-                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
-                        return null;
-                    }
+                information = SetInformation.GetSetInformation(subcommand.InformationBytes, subcommand.InformationLevel);
+            }
+            catch(UnsupportedInformationLevelException)
+            {
+                header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
+                return null;
+            }
+            catch(Exception)
+            {
+                header.Status = NTStatus.STATUS_INVALID_PARAMETER;
+                return null;
+            }
 
-                    try
-                    {
-                        share.FileSystem.SetDates(openFile.Path, info.CreationTime, info.LastWriteTime, info.LastAccessTime);
-                    }
-                    catch (IOException ex)
-                    {
-                        ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
-                        if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
-                        {
-                            // Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid
-                            state.LogToServer(Severity.Debug, "Transaction2SetFileInformation: Sharing violation setting file dates, Path: '{0}'", openFile.Path);
-                            header.Status = NTStatus.STATUS_SHARING_VIOLATION;
-                            return null;
-                        }
-                        else
-                        {
-                            header.Status = NTStatus.STATUS_DATA_ERROR;
-                            return null;
-                        }
-                    }
-                    catch (UnauthorizedAccessException)
-                    {
-                        header.Status = NTStatus.STATUS_ACCESS_DENIED;
-                        return null;
-                    }
-                    return response;
-                }
-                case SetInformationLevel.SMB_SET_FILE_DISPOSITION_INFO:
-                {
-                    if (((SetFileDispositionInfo)subcommand.SetInfo).DeletePending)
-                    {
-                        // We're supposed to delete the file on close, but it's too late to report errors at this late stage
-                        if (!share.HasWriteAccess(session.UserName))
-                        {
-                            header.Status = NTStatus.STATUS_ACCESS_DENIED;
-                            return null;
-                        }
+            if (!share.HasWriteAccess(session.UserName))
+            {
+                header.Status = NTStatus.STATUS_ACCESS_DENIED;
+                return null;
+            }
 
-                        if (openFile.Stream != null)
-                        {
-                            openFile.Stream.Close();
-                        }
-                        try
-                        {
-                            state.LogToServer(Severity.Information, "NTCreate: Deleting file '{0}'", openFile.Path);
-                            share.FileSystem.Delete(openFile.Path);
-                        }
-                        catch (IOException)
-                        {
-                            state.LogToServer(Severity.Information, "NTCreate: Error deleting '{0}'", openFile.Path);
-                            header.Status = NTStatus.STATUS_SHARING_VIOLATION;
-                            return null;
-                        }
-                        catch (UnauthorizedAccessException)
-                        {
-                            state.LogToServer(Severity.Information, "NTCreate: Error deleting '{0}', Access Denied", openFile.Path);
-                            header.Status = NTStatus.STATUS_ACCESS_DENIED;
-                            return null;
-                        }
-                    }
-                    return response;
-                }
-                case SetInformationLevel.SMB_SET_FILE_ALLOCATION_INFO:
-                {
-                    // This subcommand is used to set the file length in bytes.
-                    // Note: the input will NOT be a multiple of the cluster size / bytes per sector.
-                    ulong allocationSize = ((SetFileAllocationInfo)subcommand.SetInfo).AllocationSize;
-                    try
-                    {
-                        openFile.Stream.SetLength((long)allocationSize);
-                    }
-                    catch (IOException)
-                    {
-                        state.LogToServer(Severity.Debug, "SMB_SET_FILE_ALLOCATION_INFO: Cannot set allocation for '{0}'", openFile.Path);
-                    }
-                    catch (UnauthorizedAccessException)
-                    {
-                        state.LogToServer(Severity.Debug, "SMB_SET_FILE_ALLOCATION_INFO: Cannot set allocation for '{0}'. Access Denied", openFile.Path);
-                    }
-                    return response;
-                }
-                case SetInformationLevel.SMB_SET_FILE_END_OF_FILE_INFO:
-                {
-                    ulong endOfFile = ((SetFileEndOfFileInfo)subcommand.SetInfo).EndOfFile;
-                    try
-                    {
-                        openFile.Stream.SetLength((long)endOfFile);
-                    }
-                    catch (IOException)
-                    {
-                        state.LogToServer(Severity.Debug, "SMB_SET_FILE_END_OF_FILE_INFO: Cannot set end of file for '{0}'", openFile.Path);
-                    }
-                    catch (UnauthorizedAccessException)
-                    {
-                        state.LogToServer(Severity.Debug, "SMB_SET_FILE_END_OF_FILE_INFO: Cannot set end of file for '{0}'. Access Denied", openFile.Path);
-                    }
-                    return response;
-                }
-                default:
-                {
-                    throw new InvalidRequestException();
-                }
+            NTStatus status = SMB1FileSystemHelper.SetFileInformation(share.FileSystem, openFile, information, state);
+            if (status != NTStatus.STATUS_SUCCESS)
+            {
+                state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", openFile.Path, information.InformationLevel, status);
+                header.Status = status;
+                return null;
             }
+            Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse();
+            return response;
         }
     }
 }