Browse Source

SMB1Client: Additional client functions implemented

Tal Aloni 7 years ago
parent
commit
ff9d16cb39

+ 40 - 0
SMBLibrary/Client/SMB1Client.cs

@@ -12,6 +12,7 @@ using System.Net.Sockets;
 using System.Threading;
 using SMBLibrary.Authentication.NTLM;
 using SMBLibrary.NetBios;
+using SMBLibrary.Services;
 using SMBLibrary.SMB1;
 using Utilities;
 
@@ -28,6 +29,7 @@ namespace SMBLibrary.Client
 
         private SMBTransportType m_transport;
         private bool m_isConnected;
+        private bool m_isLoggedIn;
         private Socket m_clientSocket;
         private IAsyncResult m_currentAsyncResult;
         private bool m_forceExtendedSecurity;
@@ -186,6 +188,7 @@ namespace SMBLibrary.Client
                 SMB1Message reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
                 if (reply != null)
                 {
+                    m_isLoggedIn = (reply.Header.Status == NTStatus.STATUS_SUCCESS);
                     return reply.Header.Status;
                 }
                 return NTStatus.STATUS_INVALID_SMB;
@@ -217,6 +220,7 @@ namespace SMBLibrary.Client
                         reply = WaitForMessage(CommandName.SMB_COM_SESSION_SETUP_ANDX);
                         if (reply != null)
                         {
+                            m_isLoggedIn = (reply.Header.Status == NTStatus.STATUS_SUCCESS);
                             return reply.Header.Status;
                         }
                     }
@@ -229,8 +233,44 @@ namespace SMBLibrary.Client
             }
         }
 
+        public NTStatus Logoff()
+        {
+            LogoffAndXRequest request = new LogoffAndXRequest();
+            TrySendMessage(request);
+
+            SMB1Message reply = WaitForMessage(CommandName.SMB_COM_LOGOFF_ANDX);
+            if (reply != null)
+            {
+                m_isLoggedIn = (reply.Header.Status != NTStatus.STATUS_SUCCESS);
+                return reply.Header.Status;
+            }
+            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");
+            }
+
+
+            SMB1FileStore namedPipeShare = TreeConnect("IPC$", ServiceName.NamedPipe, out status);
+            if (namedPipeShare == null)
+            {
+                return null;
+            }
+
+            return ServerServiceHelper.ListShares(namedPipeShare, ShareType.DiskDrive, out status);
+        }
+
         public SMB1FileStore TreeConnect(string shareName, ServiceName serviceName, out NTStatus status)
         {
+            if (!m_isConnected || !m_isLoggedIn)
+            {
+                throw new InvalidOperationException("A login session must be successfully established before connecting to a share");
+            }
+
             TreeConnectAndXRequest request = new TreeConnectAndXRequest();
             request.Path = shareName;
             request.Service = serviceName;

+ 105 - 0
SMBLibrary/Client/ServerServiceHelper.cs

@@ -0,0 +1,105 @@
+/* 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 SMBLibrary.RPC;
+using SMBLibrary.Services;
+
+namespace SMBLibrary.Client
+{
+    public class ServerServiceHelper
+    {
+        public static List<string> ListShares(INTFileStore namedPipeShare, ShareType? shareType, out NTStatus status)
+        {
+            object pipeHandle;
+            FileStatus fileStatus;
+            status = namedPipeShare.CreateFile(out pipeHandle, out fileStatus, ServerService.ServicePipeName, (AccessMask)(FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA), 0, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, 0, null);
+            if (status != NTStatus.STATUS_SUCCESS)
+            {
+                return null;
+            }
+            BindPDU bindPDU = new BindPDU();
+            bindPDU.Flags = PacketFlags.FirstFragment | PacketFlags.LastFragment;
+            bindPDU.DataRepresentation.CharacterFormat = CharacterFormat.ASCII;
+            bindPDU.DataRepresentation.ByteOrder = ByteOrder.LittleEndian;
+            bindPDU.DataRepresentation.FloatingPointRepresentation = FloatingPointRepresentation.IEEE;
+            bindPDU.MaxTransmitFragmentSize = 5680;
+            bindPDU.MaxReceiveFragmentSize = 5680;
+
+            ContextElement serverServiceContext = new ContextElement();
+            serverServiceContext.AbstractSyntax = new SyntaxID(ServerService.ServiceInterfaceGuid, ServerService.ServiceVersion);
+            serverServiceContext.TransferSyntaxList.Add(new SyntaxID(RemoteServiceHelper.NDRTransferSyntaxIdentifier, RemoteServiceHelper.NDRTransferSyntaxVersion));
+            
+            bindPDU.ContextList.Add(serverServiceContext);
+
+            byte[] input = bindPDU.GetBytes();
+            byte[] output;
+            status = namedPipeShare.DeviceIOControl(pipeHandle, (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE, input, out output, 4096);
+            if (status != NTStatus.STATUS_SUCCESS)
+            {
+                return null;
+            }
+            BindAckPDU bindAckPDU = RPCPDU.GetPDU(output, 0) as BindAckPDU;
+            if (bindAckPDU == null)
+            {
+                status = NTStatus.STATUS_NOT_SUPPORTED;
+                return null;
+            }
+
+            NetrShareEnumRequest shareEnumRequest = new NetrShareEnumRequest();
+            shareEnumRequest.InfoStruct = new ShareEnum();
+            shareEnumRequest.InfoStruct.Level = 1;
+            shareEnumRequest.InfoStruct.Info = new ShareInfo1Container();
+            shareEnumRequest.PreferedMaximumLength = UInt32.MaxValue;
+            shareEnumRequest.ServerName = "*";
+            RequestPDU requestPDU = new RequestPDU();
+            requestPDU.Flags = PacketFlags.FirstFragment | PacketFlags.LastFragment;
+            requestPDU.DataRepresentation.CharacterFormat = CharacterFormat.ASCII;
+            requestPDU.DataRepresentation.ByteOrder = ByteOrder.LittleEndian;
+            requestPDU.DataRepresentation.FloatingPointRepresentation = FloatingPointRepresentation.IEEE;
+            requestPDU.OpNum = (ushort)ServerServiceOpName.NetrShareEnum;
+            requestPDU.Data = shareEnumRequest.GetBytes();
+            requestPDU.AllocationHint = (uint)requestPDU.Data.Length;
+            input = requestPDU.GetBytes();
+            status = namedPipeShare.DeviceIOControl(pipeHandle, (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE, input, out output, 4096);
+            if (status != NTStatus.STATUS_SUCCESS)
+            {
+                return null;
+            }
+            ResponsePDU responsePDU = RPCPDU.GetPDU(output, 0) as ResponsePDU;
+            if (responsePDU == null)
+            {
+                status = NTStatus.STATUS_NOT_SUPPORTED;
+                return null;
+            }
+            NetrShareEnumResponse shareEnumResponse = new NetrShareEnumResponse(responsePDU.Data);
+            ShareInfo1Container shareInfo1 = shareEnumResponse.InfoStruct.Info as ShareInfo1Container;
+            if (shareInfo1 == null)
+            {
+                if (shareEnumResponse.Result == Win32Error.ERROR_ACCESS_DENIED)
+                {
+                    status = NTStatus.STATUS_ACCESS_DENIED;
+                }
+                else
+                {
+                    status = NTStatus.STATUS_NOT_SUPPORTED;
+                }
+                return null;
+            }
+
+            List<string> result = new List<string>();
+            foreach (ShareInfo1Entry entry in shareInfo1.Entries)
+            {
+                if (!shareType.HasValue || shareType.Value == entry.ShareType.ShareType)
+                {
+                    result.Add(entry.NetName.Value);
+                }
+            }
+            return result;
+        }
+    }
+}

+ 1 - 0
SMBLibrary/SMBLibrary.csproj

@@ -57,6 +57,7 @@
     <Compile Include="Client\ConnectionState.cs" />
     <Compile Include="Client\Enums\AuthenticationMethod.cs" />
     <Compile Include="Client\NTLMAuthenticationHelper.cs" />
+    <Compile Include="Client\ServerServiceHelper.cs" />
     <Compile Include="Client\SMB1Client.cs" />
     <Compile Include="Client\SMB1FileStore.cs" />
     <Compile Include="Enums\NTStatus.cs" />