diff --git a/ClientExamples.md b/ClientExamples.md index d96e87c..67dc699 100644 --- a/ClientExamples.md +++ b/ClientExamples.md @@ -11,6 +11,7 @@ if (isConnected) List shares = client.ListShares(out status); client.Logoff(); } + client.Disconnect(); } ``` @@ -93,7 +94,7 @@ status = fileStore.Disconnect(); Create a file and write to it: ============================== ``` -ISMBFileStore fileStore = client.TreeConnect("Shared", out status); +ISMBFileStore fileStore = client.TreeConnect("Shared", out status); string filePath = "NewFile.txt"; if (fileStore is SMB1FileStore) { @@ -116,10 +117,52 @@ if (status == NTStatus.STATUS_SUCCESS) status = fileStore.Disconnect(); ``` +Write a large file: +=================== +``` +ISMBFileStore fileStore = client.TreeConnect("Shared", out status); +if (status != NTStatus.STATUS_SUCCESS) +{ + throw new Exception("Failed to connect to share"); +} +string localFilePath = @"C:\Image.jpg"; +string remoteFilePath = "NewFile.jpg"; +if (fileStore is SMB1FileStore) +{ + remoteFilePath = @"\\" + remoteFilePath; +} +FileStream localFileStream = new FileStream(localFilePath, FileMode.Open, FileAccess.Read); +object fileHandle; +FileStatus fileStatus; +status = fileStore.CreateFile(out fileHandle, out fileStatus, remoteFilePath, AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE, FileAttributes.Normal, ShareAccess.None, CreateDisposition.FILE_CREATE, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null); +if (status == NTStatus.STATUS_SUCCESS) +{ + int writeOffset = 0; + while (localFileStream.Position < localFileStream.Length) + { + byte[] buffer = new byte[(int)client.MaxWriteSize]; + int bytesRead = localFileStream.Read(buffer, 0, buffer.Length); + if (bytesRead < (int)client.MaxWriteSize) + { + Array.Resize(ref buffer, bytesRead); + } + int numberOfBytesWritten; + status = fileStore.WriteFile(out numberOfBytesWritten, fileHandle, writeOffset, buffer); + if (status != NTStatus.STATUS_SUCCESS) + { + throw new Exception("Failed to write to file"); + } + writeOffset += bytesRead; + } + status = fileStore.CloseFile(fileHandle); +} +status = fileStore.Disconnect(); +``` + Delete file: ============ ``` -ISMBFileStore fileStore = client.TreeConnect("Shared", out status); +ISMBFileStore fileStore = client.TreeConnect("Shared", out status); string filePath = "DeleteMe.txt"; if (fileStore is SMB1FileStore) { diff --git a/SMBLibrary.Adapters/Properties/AssemblyInfo.cs b/SMBLibrary.Adapters/Properties/AssemblyInfo.cs index fc116cf..5bfe40d 100644 --- a/SMBLibrary.Adapters/Properties/AssemblyInfo.cs +++ b/SMBLibrary.Adapters/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.4.6.0")] -[assembly: AssemblyFileVersion("1.4.6.0")] +[assembly: AssemblyVersion("1.4.8.0")] +[assembly: AssemblyFileVersion("1.4.8.0")] diff --git a/SMBLibrary.Adapters/SMBLibrary.Adapters.csproj b/SMBLibrary.Adapters/SMBLibrary.Adapters.csproj index f7440e1..9f33030 100644 --- a/SMBLibrary.Adapters/SMBLibrary.Adapters.csproj +++ b/SMBLibrary.Adapters/SMBLibrary.Adapters.csproj @@ -4,7 +4,7 @@ net20;net40;netstandard2.0 false SMBLibrary.Adapters - 1.4.6 + 1.4.8 1573;1591 SMBLibrary.Adapters Tal Aloni diff --git a/SMBLibrary.Win32/Properties/AssemblyInfo.cs b/SMBLibrary.Win32/Properties/AssemblyInfo.cs index 7588932..13a5087 100644 --- a/SMBLibrary.Win32/Properties/AssemblyInfo.cs +++ b/SMBLibrary.Win32/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.4.6.0")] -[assembly: AssemblyFileVersion("1.4.6.0")] +[assembly: AssemblyVersion("1.4.8.0")] +[assembly: AssemblyFileVersion("1.4.8.0")] diff --git a/SMBLibrary.Win32/SMBLibrary.Win32.csproj b/SMBLibrary.Win32/SMBLibrary.Win32.csproj index 4eec41c..e1b17c4 100644 --- a/SMBLibrary.Win32/SMBLibrary.Win32.csproj +++ b/SMBLibrary.Win32/SMBLibrary.Win32.csproj @@ -4,7 +4,7 @@ net20;net40;netstandard2.0 false SMBLibrary.Win32 - 1.4.6 + 1.4.8 1573;1591 SMBLibrary.Win32 Tal Aloni diff --git a/SMBLibrary/Client/Helpers/ServerServiceHelper.cs b/SMBLibrary/Client/Helpers/ServerServiceHelper.cs index 6d3c21d..39d0645 100644 --- a/SMBLibrary/Client/Helpers/ServerServiceHelper.cs +++ b/SMBLibrary/Client/Helpers/ServerServiceHelper.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2014-2020 Tal Aloni . All rights reserved. +/* Copyright (C) 2014-2021 Tal Aloni . 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, @@ -15,6 +15,15 @@ namespace SMBLibrary.Client public class ServerServiceHelper { public static List ListShares(INTFileStore namedPipeShare, ShareType? shareType, out NTStatus status) + { + return ListShares(namedPipeShare, "*", shareType, out status); + } + + /// + /// When a Windows Server host is using Failover Cluster and Cluster Shared Volumes, each of those CSV file shares is associated + /// with a specific host name associated with the cluster and is not accessible using the node IP address or node host name. + /// + public static List ListShares(INTFileStore namedPipeShare, string serverName, ShareType? shareType, out NTStatus status) { object pipeHandle; int maxTransmitFragmentSize; @@ -29,7 +38,7 @@ namespace SMBLibrary.Client shareEnumRequest.InfoStruct.Level = 1; shareEnumRequest.InfoStruct.Info = new ShareInfo1Container(); shareEnumRequest.PreferedMaximumLength = UInt32.MaxValue; - shareEnumRequest.ServerName = "*"; + shareEnumRequest.ServerName = @"\\" + serverName; RequestPDU requestPDU = new RequestPDU(); requestPDU.Flags = PacketFlags.FirstFragment | PacketFlags.LastFragment; requestPDU.DataRepresentation.CharacterFormat = CharacterFormat.ASCII; diff --git a/SMBLibrary/Client/ISMBClient.cs b/SMBLibrary/Client/ISMBClient.cs index abf503f..6bb255f 100644 --- a/SMBLibrary/Client/ISMBClient.cs +++ b/SMBLibrary/Client/ISMBClient.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Tal Aloni . All rights reserved. +/* Copyright (C) 2017-2021 Tal Aloni . 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, diff --git a/SMBLibrary/Client/SMB1Client.cs b/SMBLibrary/Client/SMB1Client.cs index cad06e1..c24476a 100644 --- a/SMBLibrary/Client/SMB1Client.cs +++ b/SMBLibrary/Client/SMB1Client.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2014-2020 Tal Aloni . All rights reserved. +/* Copyright (C) 2014-2021 Tal Aloni . 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, @@ -29,6 +29,7 @@ namespace SMBLibrary.Client private static readonly ushort ClientMaxBufferSize = 65535; // Valid range: 512 - 65535 private static readonly ushort ClientMaxMpxCount = 1; + private static readonly int ResponseTimeoutInMilliseconds = 5000; private SMBTransportType m_transport; private bool m_isConnected; @@ -81,8 +82,7 @@ namespace SMBLibrary.Client if (!m_isConnected) { m_forceExtendedSecurity = forceExtendedSecurity; - int port; - port = transport == SMBTransportType.NetBiosOverTCP ? NetBiosOverTCPPort : DirectTCPPort; + var port = transport == SMBTransportType.NetBiosOverTCP ? NetBiosOverTCPPort : DirectTCPPort; if (!await ConnectSocketAsync(serverAddress, port)) { @@ -749,10 +749,9 @@ namespace SMBLibrary.Client internal SMB1Message WaitForMessage(CommandName commandName) { - const int TimeOut = 5000; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - while (stopwatch.ElapsedMilliseconds < TimeOut) + while (stopwatch.ElapsedMilliseconds < ResponseTimeoutInMilliseconds) { lock (m_incomingQueueLock) { diff --git a/SMBLibrary/Client/SMB2Client.cs b/SMBLibrary/Client/SMB2Client.cs index c89dabf..c270b78 100644 --- a/SMBLibrary/Client/SMB2Client.cs +++ b/SMBLibrary/Client/SMB2Client.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2020 Tal Aloni . All rights reserved. +/* Copyright (C) 2017-2021 Tal Aloni . 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, @@ -9,12 +9,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.Sockets; -using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; -using SMBLibrary.Authentication.NTLM; using SMBLibrary.NetBios; -using SMBLibrary.Services; using SMBLibrary.SMB2; using Utilities; @@ -28,8 +25,10 @@ namespace SMBLibrary.Client public static readonly uint ClientMaxTransactSize = 1048576; public static readonly uint ClientMaxReadSize = 1048576; public static readonly uint ClientMaxWriteSize = 1048576; - private static readonly ushort DesiredCredits = 16; + private static readonly ushort DesiredCredits = 16; + public static readonly int ResponseTimeoutInMilliseconds = 5000; + private string m_serverName; private SMBTransportType m_transport; private bool m_isConnected; private bool m_isLoggedIn; @@ -63,11 +62,15 @@ namespace SMBLibrary.Client public bool Connect(IPAddress serverAddress, SMBTransportType transport, string serverName = null) { + if (m_serverName == null) + { + m_serverName = serverAddress.ToString(); + } + m_transport = transport; if (!m_isConnected) { - int port; - port = transport == SMBTransportType.NetBiosOverTCP ? NetBiosOverTCPPort : DirectTCPPort; + var port = transport == SMBTransportType.NetBiosOverTCP ? NetBiosOverTCPPort : DirectTCPPort; if (!ConnectSocket(serverAddress, port)) { @@ -294,7 +297,7 @@ namespace SMBLibrary.Client request.Dialects.Add(SMB2Dialect.SMB300); TrySendCommand(request); - NegotiateResponse response = WaitForCommand(SMB2CommandName.Negotiate) as NegotiateResponse; + NegotiateResponse response = WaitForCommand(request.MessageID) as NegotiateResponse; if (response != null && response.Header.Status == NTStatus.STATUS_SUCCESS) { m_dialect = response.DialectRevision; @@ -327,7 +330,7 @@ namespace SMBLibrary.Client SecurityBuffer = negotiateMessage }; TrySendCommand(request); - var response = WaitForCommand(SMB2CommandName.SessionSetup); + var response = WaitForCommand(request.MessageID); if (response != null && response.Header.Status == NTStatus.STATUS_MORE_PROCESSING_REQUIRED && response is SessionSetupResponse ssr) @@ -359,7 +362,7 @@ namespace SMBLibrary.Client request.SecurityMode = SecurityMode.SigningEnabled; request.SecurityBuffer = negotiateMessage; TrySendCommand(request); - SMB2Command response = WaitForCommand(SMB2CommandName.SessionSetup); + SMB2Command response = WaitForCommand(request.MessageID); if (response != null) { if (response.Header.Status == NTStatus.STATUS_MORE_PROCESSING_REQUIRED && response is SessionSetupResponse) @@ -375,7 +378,7 @@ namespace SMBLibrary.Client request.SecurityMode = SecurityMode.SigningEnabled; request.SecurityBuffer = authenticateMessage; TrySendCommand(request); - response = WaitForCommand(SMB2CommandName.SessionSetup); + response = WaitForCommand(request.MessageID); if (response != null) { m_isLoggedIn = (response.Header.Status == NTStatus.STATUS_SUCCESS); @@ -410,7 +413,7 @@ namespace SMBLibrary.Client LogoffRequest request = new LogoffRequest(); TrySendCommand(request); - SMB2Command response = WaitForCommand(SMB2CommandName.Logoff); + SMB2Command response = WaitForCommand(request.MessageID); if (response != null) { m_isLoggedIn = (response.Header.Status != NTStatus.STATUS_SUCCESS); @@ -432,7 +435,7 @@ namespace SMBLibrary.Client return null; } - List shares = ServerServiceHelper.ListShares(namedPipeShare, SMBLibrary.Services.ShareType.DiskDrive, out status); + List shares = ServerServiceHelper.ListShares(namedPipeShare, m_serverName, SMBLibrary.Services.ShareType.DiskDrive, out status); namedPipeShare.Disconnect(); return shares; } @@ -444,12 +447,11 @@ namespace SMBLibrary.Client 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); + string sharePath = String.Format(@"\\{0}\{1}", m_serverName, shareName); TreeConnectRequest request = new TreeConnectRequest(); request.Path = sharePath; TrySendCommand(request); - SMB2Command response = WaitForCommand(SMB2CommandName.TreeConnect); + SMB2Command response = WaitForCommand(request.MessageID); if (response != null) { status = response.Header.Status; @@ -621,12 +623,11 @@ namespace SMBLibrary.Client } } - internal SMB2Command WaitForCommand(SMB2CommandName commandName) + internal SMB2Command WaitForCommand(ulong messageID) { - const int TimeOut = 5000; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - while (stopwatch.ElapsedMilliseconds < TimeOut) + while (stopwatch.ElapsedMilliseconds < ResponseTimeoutInMilliseconds) { lock (m_incomingQueueLock) { @@ -634,9 +635,14 @@ namespace SMBLibrary.Client { SMB2Command command = m_incomingQueue[index]; - if (command.CommandName == commandName) + if (command.Header.MessageID == messageID) { m_incomingQueue.RemoveAt(index); + if (command.Header.IsAsync && command.Header.Status == NTStatus.STATUS_PENDING) + { + index--; + continue; + } return command; } } diff --git a/SMBLibrary/Client/SMB2FileStore.cs b/SMBLibrary/Client/SMB2FileStore.cs index 551958c..64607d7 100644 --- a/SMBLibrary/Client/SMB2FileStore.cs +++ b/SMBLibrary/Client/SMB2FileStore.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2020 Tal Aloni . All rights reserved. +/* Copyright (C) 2017-2021 Tal Aloni . 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, @@ -40,7 +40,7 @@ namespace SMBLibrary.Client request.ImpersonationLevel = ImpersonationLevel.Impersonation; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Create); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is CreateResponse) @@ -60,7 +60,7 @@ namespace SMBLibrary.Client CloseRequest request = new CloseRequest(); request.FileId = (FileID)handle; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Close); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { return response.Header.Status; @@ -79,7 +79,7 @@ namespace SMBLibrary.Client request.ReadLength = (uint)maxCount; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Read); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is ReadResponse) @@ -102,7 +102,7 @@ namespace SMBLibrary.Client request.Data = data; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.Write); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is WriteResponse) @@ -117,7 +117,20 @@ namespace SMBLibrary.Client public NTStatus FlushFileBuffers(object handle) { - throw new NotImplementedException(); + FlushRequest request = new FlushRequest(); + request.FileId = (FileID) handle; + + TrySendCommand(request); + SMB2Command response = m_client.WaitForCommand(request.MessageID); + if (response != null) + { + if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is FlushResponse) + { + return response.Header.Status; + } + } + + return NTStatus.STATUS_INVALID_SMB; } public NTStatus LockFile(object handle, long byteOffset, long length, bool exclusiveLock) @@ -142,7 +155,7 @@ namespace SMBLibrary.Client request.FileName = fileName; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.QueryDirectory); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { while (response.Header.Status == NTStatus.STATUS_SUCCESS && response is QueryDirectoryResponse) @@ -151,7 +164,7 @@ namespace SMBLibrary.Client result.AddRange(page); request.Reopen = false; TrySendCommand(request); - response = m_client.WaitForCommand(SMB2CommandName.QueryDirectory); + response = m_client.WaitForCommand(request.MessageID); } return response.Header.Status; } @@ -169,7 +182,7 @@ namespace SMBLibrary.Client request.FileId = (FileID)handle; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.QueryInfo); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is QueryInfoResponse) @@ -191,7 +204,7 @@ namespace SMBLibrary.Client request.SetFileInformation(information); TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.SetInfo); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { return response.Header.Status; @@ -226,7 +239,7 @@ namespace SMBLibrary.Client request.FileId = (FileID)handle; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.QueryInfo); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is QueryInfoResponse) @@ -254,7 +267,7 @@ namespace SMBLibrary.Client request.FileId = (FileID)handle; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.QueryInfo); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { if (response.Header.Status == NTStatus.STATUS_SUCCESS && response is QueryInfoResponse) @@ -293,7 +306,7 @@ namespace SMBLibrary.Client request.Input = input; request.MaxOutputResponse = (uint)maxOutputLength; TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.IOCtl); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { if ((response.Header.Status == NTStatus.STATUS_SUCCESS || response.Header.Status == NTStatus.STATUS_BUFFER_OVERFLOW) && response is IOCtlResponse) @@ -310,7 +323,7 @@ namespace SMBLibrary.Client { TreeDisconnectRequest request = new TreeDisconnectRequest(); TrySendCommand(request); - SMB2Command response = m_client.WaitForCommand(SMB2CommandName.TreeDisconnect); + SMB2Command response = m_client.WaitForCommand(request.MessageID); if (response != null) { return response.Header.Status; diff --git a/SMBLibrary/Enums/NTStatus.cs b/SMBLibrary/Enums/NTStatus.cs index f8eb2ac..9ce465e 100644 --- a/SMBLibrary/Enums/NTStatus.cs +++ b/SMBLibrary/Enums/NTStatus.cs @@ -37,6 +37,7 @@ namespace SMBLibrary STATUS_LOCK_NOT_GRANTED = 0xC0000055, STATUS_DELETE_PENDING = 0xC0000056, STATUS_PRIVILEGE_NOT_HELD = 0xC0000061, + STATUS_WRONG_PASSWORD = 0xC000006A, STATUS_LOGON_FAILURE = 0xC000006D, // Authentication failure. STATUS_ACCOUNT_RESTRICTION = 0xC000006E, // The user has an empty password, which is not allowed STATUS_INVALID_LOGON_HOURS = 0xC000006F, @@ -64,9 +65,10 @@ namespace SMBLibrary STATUS_FS_DRIVER_REQUIRED = 0xC000019C, STATUS_USER_SESSION_DELETED = 0xC0000203, STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205, + STATUS_PASSWORD_MUST_CHANGE = 0xC0000224, STATUS_NOT_FOUND = 0xC0000225, STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234, - STATUS_PASSWORD_MUST_CHANGE = 0xC0000244, + STATUS_PATH_NOT_COVERED = 0xC0000257, STATUS_NOT_A_REPARSE_POINT = 0xC0000275, STATUS_INVALID_SMB = 0x00010002, // SMB1/CIFS: A corrupt or invalid SMB request was received diff --git a/SMBLibrary/Helpers/SP800_1008.cs b/SMBLibrary/Helpers/SP800_1008.cs index 0ac7684..1c78512 100644 --- a/SMBLibrary/Helpers/SP800_1008.cs +++ b/SMBLibrary/Helpers/SP800_1008.cs @@ -1,4 +1,4 @@ -/// Adapted from https://referencesource.microsoft.com/#system.web/Security/Cryptography/SP800_108.cs +// Adapted from https://referencesource.microsoft.com/#system.web/Security/Cryptography/SP800_108.cs using System; using System.Security.Cryptography; using Utilities; diff --git a/SMBLibrary/NTFileStore/Structures/FileInformation/FileInformation.cs b/SMBLibrary/NTFileStore/Structures/FileInformation/FileInformation.cs index b841527..b0b3843 100644 --- a/SMBLibrary/NTFileStore/Structures/FileInformation/FileInformation.cs +++ b/SMBLibrary/NTFileStore/Structures/FileInformation/FileInformation.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Tal Aloni . All rights reserved. +/* Copyright (C) 2017-2021 Tal Aloni . 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, @@ -88,7 +88,7 @@ namespace SMBLibrary case FileInformationClass.FileShortNameInformation: throw new NotImplementedException(); default: - throw new UnsupportedInformationLevelException(); + throw new UnsupportedInformationLevelException(String.Format("Unsupported information class: {0}", informationClass)); } } } diff --git a/SMBLibrary/NetBios/NetBiosUtils.cs b/SMBLibrary/NetBios/NetBiosUtils.cs index 67fb9b1..1661222 100644 --- a/SMBLibrary/NetBios/NetBiosUtils.cs +++ b/SMBLibrary/NetBios/NetBiosUtils.cs @@ -60,7 +60,7 @@ namespace SMBLibrary.NetBios return EncodeName(netBiosName, scopeID); } - /// NetBIOS name + /// NetBIOS name /// dot-separated labels, formatted per DNS naming rules public static byte[] EncodeName(string netBiosName, string scopeID) { @@ -75,7 +75,7 @@ namespace SMBLibrary.NetBios // into two nibbles and then adding the value of 'A' (0x41). // Thus, the '&' character (0x26) would be encoded as "CG". // NetBIOS names are usually padded with spaces before being encoded. - /// NetBIOS name + /// NetBIOS name /// dot-separated labels, formatted per DNS naming rules public static string FirstLevelEncoding(string netBiosName, string scopeID) { diff --git a/SMBLibrary/Properties/AssemblyInfo.cs b/SMBLibrary/Properties/AssemblyInfo.cs index 76ba17f..e2d24a4 100644 --- a/SMBLibrary/Properties/AssemblyInfo.cs +++ b/SMBLibrary/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.4.6.0")] -[assembly: AssemblyFileVersion("1.4.6.0")] +[assembly: AssemblyVersion("1.4.8.0")] +[assembly: AssemblyFileVersion("1.4.8.0")] [assembly: InternalsVisibleTo("SMBLibrary.Tests")] \ No newline at end of file diff --git a/SMBLibrary/RevisionHistory.txt b/SMBLibrary/RevisionHistory.txt index d03156b..678b1b7 100644 --- a/SMBLibrary/RevisionHistory.txt +++ b/SMBLibrary/RevisionHistory.txt @@ -459,3 +459,15 @@ Revision History: NTLM: Bugfix: IndependentNTLMAuthenticationProvider login failed to to modification of message byte arrays. 1.4.6 - SMB2Client: Fixed InvalidCastException on failed login to SMB 3.0 server. + +1.4.7 - SMBServer: Added private Start overload allowing to specify the listening port. + Client: Added private Connect overload allowing to specify the server port. + SMB2Client: Correctly handle async responses. + SMB2Client: WaitForCommand: Compare MessageID instead of CommandName. + Client: SMB2FileStore: Implement Flush. + Client: Added support for accessing Cluster Shared Volumes file shares. + SMB2Command: Add MessageID property. + NTStatus: Added STATUS_WRONG_PASSWORD. + NTStatus: Correct STATUS_PASSWORD_MUST_CHANGE value. + +1.4.8 - SMBServer - Start method bugfix. diff --git a/SMBLibrary/SMB1/Transaction2Subcommands/Transaction2QueryFileInformationResponse.cs b/SMBLibrary/SMB1/Transaction2Subcommands/Transaction2QueryFileInformationResponse.cs index 75b156b..bc750c1 100644 --- a/SMBLibrary/SMB1/Transaction2Subcommands/Transaction2QueryFileInformationResponse.cs +++ b/SMBLibrary/SMB1/Transaction2Subcommands/Transaction2QueryFileInformationResponse.cs @@ -12,7 +12,7 @@ namespace SMBLibrary.SMB1 { /// /// TRANS2_QUERY_FILE_INFORMATION Response - /// public class Transaction2QueryFileInformationResponse : Transaction2Subcommand { public const int ParametersLength = 2; diff --git a/SMBLibrary/SMB2/Commands/SMB2Command.cs b/SMBLibrary/SMB2/Commands/SMB2Command.cs index 23b3796..479aa36 100644 --- a/SMBLibrary/SMB2/Commands/SMB2Command.cs +++ b/SMBLibrary/SMB2/Commands/SMB2Command.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2020 Tal Aloni . All rights reserved. +/* Copyright (C) 2017-2021 Tal Aloni . 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, @@ -49,6 +49,14 @@ namespace SMBLibrary.SMB2 } } + public ulong MessageID + { + get + { + return Header.MessageID; + } + } + public int Length { get @@ -127,7 +135,7 @@ namespace SMBLibrary.SMB2 return GetCommandChainBytes(commands, null, SMB2Dialect.SMB2xx); } - /// + /// /// Message will be signed using this key if (not null and) SMB2_FLAGS_SIGNED is set. /// /// diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj index 9c971f2..b31bedb 100644 --- a/SMBLibrary/SMBLibrary.csproj +++ b/SMBLibrary/SMBLibrary.csproj @@ -6,6 +6,7 @@ false SMBLibrary 1.6.0 + 1.4.8 1573;1591 SMBLibrary false diff --git a/SMBLibrary/Server/SMBServer.cs b/SMBLibrary/Server/SMBServer.cs index c85a266..8cc48a2 100644 --- a/SMBLibrary/Server/SMBServer.cs +++ b/SMBLibrary/Server/SMBServer.cs @@ -1,4 +1,4 @@ -/* Copyright (C) 2014-2020 Tal Aloni . All rights reserved. +/* Copyright (C) 2014-2021 Tal Aloni . 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, @@ -77,6 +77,12 @@ namespace SMBLibrary.Server /// /// public void Start(IPAddress serverAddress, SMBTransportType transport, bool enableSMB1, bool enableSMB2, bool enableSMB3, TimeSpan? connectionInactivityTimeout) + { + int port = (transport == SMBTransportType.DirectTCPTransport ? DirectTCPPort : NetBiosOverTCPPort); + Start(serverAddress, transport, port, enableSMB1, enableSMB2, enableSMB3, connectionInactivityTimeout); + } + + private void Start(IPAddress serverAddress, SMBTransportType transport, int port, bool enableSMB1, bool enableSMB2, bool enableSMB3, TimeSpan? connectionInactivityTimeout) { if (!m_listening) { @@ -95,7 +101,6 @@ namespace SMBLibrary.Server m_serverStartTime = DateTime.Now; m_listenerSocket = new Socket(m_serverAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - int port = (m_transport == SMBTransportType.DirectTCPTransport ? DirectTCPPort : NetBiosOverTCPPort); m_listenerSocket.Bind(new IPEndPoint(m_serverAddress, port)); m_listenerSocket.Listen((int)SocketOptionName.MaxConnections); m_listenerSocket.BeginAccept(ConnectRequestCallback, m_listenerSocket); diff --git a/SMBLibrary/Server/Shares/SMBShareCollection.cs b/SMBLibrary/Server/Shares/SMBShareCollection.cs index 4cd61a1..0321674 100644 --- a/SMBLibrary/Server/Shares/SMBShareCollection.cs +++ b/SMBLibrary/Server/Shares/SMBShareCollection.cs @@ -39,7 +39,7 @@ namespace SMBLibrary.Server return result; } - /// e.g. \Shared + /// e.g. \Shared public FileSystemShare GetShareFromName(string shareName) { int index = IndexOf(shareName, StringComparison.OrdinalIgnoreCase); diff --git a/SMBServer/Properties/AssemblyInfo.cs b/SMBServer/Properties/AssemblyInfo.cs index 3a6ce02..de3408d 100644 --- a/SMBServer/Properties/AssemblyInfo.cs +++ b/SMBServer/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("1.4.6.0")] -[assembly: AssemblyFileVersion("1.4.6.0")] +[assembly: AssemblyVersion("1.4.8.0")] +[assembly: AssemblyFileVersion("1.4.8.0")]