Browse Source

SMB2Client: Implemented additional client functions

Tal Aloni 7 years ago
parent
commit
d15db358cb
3 changed files with 248 additions and 0 deletions
  1. 44 0
      SMBLibrary/Client/SMB2Client.cs
  2. 203 0
      SMBLibrary/Client/SMB2FileStore.cs
  3. 1 0
      SMBLibrary/SMBLibrary.csproj

+ 44 - 0
SMBLibrary/Client/SMB2Client.cs

@@ -174,6 +174,50 @@ namespace SMBLibrary.Client
             return NTStatus.STATUS_INVALID_SMB;
         }
 
+        public List<string> ListShares(out NTStatus status)
+        {
+            if (!m_isConnected || !m_isLoggedIn)
+            {
+                throw new InvalidOperationException("A login session must be successfully established before retrieving share list");
+            }
+
+            SMB2FileStore namedPipeShare = TreeConnect("IPC$", out status);
+            if (namedPipeShare == null)
+            {
+                return null;
+            }
+
+            return ServerServiceHelper.ListShares(namedPipeShare, SMBLibrary.Services.ShareType.DiskDrive, out status);
+        }
+
+        public SMB2FileStore TreeConnect(string shareName, out NTStatus status)
+        {
+            if (!m_isConnected || !m_isLoggedIn)
+            {
+                throw new InvalidOperationException("A login session must be successfully established before connecting to a share");
+            }
+
+            IPAddress serverIPAddress = ((IPEndPoint)m_clientSocket.RemoteEndPoint).Address;
+            string sharePath = String.Format(@"\\{0}\{1}", serverIPAddress.ToString(), shareName);
+            TreeConnectRequest request = new TreeConnectRequest();
+            request.Path = sharePath;
+            TrySendCommand(request);
+            SMB2Command response = WaitForCommand(SMB2CommandName.TreeConnect);
+            if (response != null)
+            {
+                status = response.Header.Status;
+                if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is TreeConnectResponse)
+                {
+                    return new SMB2FileStore(this, response.Header.TreeID);
+                }
+            }
+            else
+            {
+                status = NTStatus.STATUS_INVALID_SMB;
+            }
+            return null;
+        }
+
         private void OnClientSocketReceive(IAsyncResult ar)
         {
             if (ar != m_currentAsyncResult)

+ 203 - 0
SMBLibrary/Client/SMB2FileStore.cs

@@ -0,0 +1,203 @@
+/* Copyright (C) 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 SMBLibrary.SMB2;
+using Utilities;
+
+namespace SMBLibrary.Client
+{
+    public class SMB2FileStore : INTFileStore
+    {
+        private SMB2Client m_client;
+        private uint m_treeID;
+
+        public SMB2FileStore(SMB2Client client, uint treeID)
+        {
+            m_client = client;
+            m_treeID = treeID;
+        }
+
+        public NTStatus CreateFile(out object handle, out FileStatus fileStatus, string path, AccessMask desiredAccess, FileAttributes fileAttributes, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions, SecurityContext securityContext)
+        {
+            handle = null;
+            fileStatus = FileStatus.FILE_DOES_NOT_EXIST;
+            CreateRequest request = new CreateRequest();
+            request.Name = path;
+            request.DesiredAccess = desiredAccess;
+            request.FileAttributes = fileAttributes;
+            request.ShareAccess = shareAccess;
+            request.CreateDisposition = createDisposition;
+            request.CreateOptions = createOptions;
+            request.ImpersonationLevel = ImpersonationLevel.Impersonation;
+            TrySendCommand(request);
+
+            SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Create);
+            if (response != null)
+            {
+                if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is CreateResponse)
+                {
+                    CreateResponse createResponse = ((CreateResponse)response);
+                    handle = createResponse.FileId;
+                    fileStatus = ToFileStatus(createResponse.CreateAction);
+                }
+                return response.Header.Status;
+            }
+
+            return NTStatus.STATUS_INVALID_SMB;
+        }
+
+        public NTStatus CloseFile(object handle)
+        {
+            CloseRequest request = new CloseRequest();
+            request.FileId = (FileID)handle;
+            TrySendCommand(request);
+            SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Close);
+            if (response != null)
+            {
+                return response.Header.Status;
+            }
+
+            return NTStatus.STATUS_INVALID_SMB;
+        }
+
+        public NTStatus ReadFile(out byte[] data, object handle, long offset, int maxCount)
+        {
+            data = null;
+            ReadRequest request = new ReadRequest();
+            request.FileId = (FileID)handle;
+            request.Offset = (ulong)offset;
+            request.ReadLength = (uint)maxCount;
+            
+            TrySendCommand(request);
+            SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Read);
+            if (response != null)
+            {
+                if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is ReadResponse)
+                {
+                    data = ((ReadResponse)response).Data;
+                }
+                return response.Header.Status;
+            }
+
+            return NTStatus.STATUS_INVALID_SMB;
+        }
+
+        public NTStatus WriteFile(out int numberOfBytesWritten, object handle, long offset, byte[] data)
+        {
+            numberOfBytesWritten = 0;
+            WriteRequest request = new WriteRequest();
+            request.FileId = (FileID)handle;
+            request.Offset = (ulong)offset;
+            request.Data = data;
+
+            TrySendCommand(request);
+            SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Write);
+            if (response != null)
+            {
+                if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is WriteResponse)
+                {
+                    numberOfBytesWritten = (int)((WriteResponse)response).Count;
+                }
+                return response.Header.Status;
+            }
+
+            return NTStatus.STATUS_INVALID_SMB;
+        }
+
+        public NTStatus FlushFileBuffers(object handle)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus LockFile(object handle, long byteOffset, long length, bool exclusiveLock)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus UnlockFile(object handle, long byteOffset, long length)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus QueryDirectory(out List<QueryDirectoryFileInformation> result, object handle, string fileName, FileInformationClass informationClass)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus GetFileInformation(out FileInformation result, object handle, FileInformationClass informationClass)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus SetFileInformation(object handle, FileInformation information)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus NotifyChange(out object ioRequest, object handle, NotifyChangeFilter completionFilter, bool watchTree, int outputBufferSize, OnNotifyChangeCompleted onNotifyChangeCompleted, object context)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus Cancel(object ioRequest)
+        {
+            throw new NotImplementedException();
+        }
+
+        public NTStatus DeviceIOControl(object handle, uint ctlCode, byte[] input, out byte[] output, int maxOutputLength)
+        {
+            output = null;
+            IOCtlRequest request = new IOCtlRequest();
+            request.CtlCode = ctlCode;
+            request.IsFSCtl = true;
+            request.FileId = (FileID)handle;
+            request.Input = input;
+            request.MaxOutputResponse = (uint)maxOutputLength;
+            TrySendCommand(request);
+            SMB2Command response = m_client.WaitForCommand(SMB2CommandName.IOCtl);
+            if (response != null)
+            {
+                if ((response.Header.Status == NTStatus.STATUS_SUCCESS || response.Header.Status == NTStatus.STATUS_BUFFER_OVERFLOW) && response is IOCtlResponse)
+                {
+                    output = ((IOCtlResponse)response).Output;
+                }
+                return response.Header.Status;
+            }
+
+            return NTStatus.STATUS_INVALID_SMB;
+        }
+
+        private void TrySendCommand(SMB2Command request)
+        {
+            request.Header.TreeID = m_treeID;
+            m_client.TrySendCommand(request);
+        }
+
+        private static FileStatus ToFileStatus(CreateAction createAction)
+        {
+            switch (createAction)
+            {
+                case CreateAction.FILE_SUPERSEDED:
+                    return FileStatus.FILE_SUPERSEDED;
+                case CreateAction.FILE_OPENED:
+                    return FileStatus.FILE_OPENED;
+                case CreateAction.FILE_CREATED:
+                    return FileStatus.FILE_CREATED;
+                case CreateAction.FILE_OVERWRITTEN:
+                    return FileStatus.FILE_OVERWRITTEN;
+                default:
+                    return FileStatus.FILE_OPENED;
+            }
+        }
+    }
+}

+ 1 - 0
SMBLibrary/SMBLibrary.csproj

@@ -61,6 +61,7 @@
     <Compile Include="Client\SMB1Client.cs" />
     <Compile Include="Client\SMB1FileStore.cs" />
     <Compile Include="Client\SMB2Client.cs" />
+    <Compile Include="Client\SMB2FileStore.cs" />
     <Compile Include="Enums\NTStatus.cs" />
     <Compile Include="Enums\SMBTransportType.cs" />
     <Compile Include="Enums\Win32Error.cs" />