diff --git a/SMBLibrary/SMB2/Commands/CancelRequest.cs b/SMBLibrary/SMB2/Commands/CancelRequest.cs new file mode 100644 index 0000000..4c61b8f --- /dev/null +++ b/SMBLibrary/SMB2/Commands/CancelRequest.cs @@ -0,0 +1,48 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 CANCEL Request + /// + public class CancelRequest : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public CancelRequest() : base(SMB2CommandName.Cancel) + { + StructureSize = DeclaredSize; + } + + public CancelRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/ChangeNotifyRequest.cs b/SMBLibrary/SMB2/Commands/ChangeNotifyRequest.cs new file mode 100644 index 0000000..9263e32 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/ChangeNotifyRequest.cs @@ -0,0 +1,60 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 CHANGE_NOTIFY Request + /// + public class ChangeNotifyRequest : SMB2Command + { + public const int DeclaredSize = 32; + + public ushort StructureSize; + public ChangeNotifyFlags Flags; + public uint OutputBufferLength; + public FileID FileId; + public NotifyChange CompletionFilter; + public uint Reserved; + + public ChangeNotifyRequest() : base(SMB2CommandName.ChangeNotify) + { + StructureSize = DeclaredSize; + } + + public ChangeNotifyRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Flags = (ChangeNotifyFlags)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + OutputBufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + FileId = new FileID(buffer, offset + SMB2Header.Length + 8); + CompletionFilter = (NotifyChange)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 24); + Reserved = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 28); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, (ushort)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, OutputBufferLength); + FileId.WriteBytes(buffer, offset + 8); + LittleEndianWriter.WriteUInt32(buffer, offset + 24, (uint)CompletionFilter); + LittleEndianWriter.WriteUInt32(buffer, offset + 28, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/ChangeNotifyResponse.cs b/SMBLibrary/SMB2/Commands/ChangeNotifyResponse.cs new file mode 100644 index 0000000..1923ca5 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/ChangeNotifyResponse.cs @@ -0,0 +1,62 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 CHANGE_NOTIFY Response + /// + public class ChangeNotifyResponse : SMB2Command + { + public const int FixedSize = 8; + public const int DeclaredSize = 9; + + public ushort StructureSize; + private ushort OutputBufferOffset; + private uint OutputBufferLength; + public byte[] OutputBuffer = new byte[0]; + + public ChangeNotifyResponse() : base(SMB2CommandName.ChangeNotify) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public ChangeNotifyResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + OutputBufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + OutputBufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + OutputBuffer = ByteReader.ReadBytes(buffer, offset + OutputBufferOffset, (int)OutputBufferLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + OutputBufferOffset = 0; + OutputBufferLength = (uint)OutputBuffer.Length; + if (OutputBuffer.Length > 0) + { + OutputBufferOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, OutputBufferOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, OutputBufferLength); + ByteWriter.WriteBytes(buffer, offset + FixedSize, OutputBuffer); + } + + public override int CommandLength + { + get + { + return FixedSize + OutputBuffer.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/CloseRequest.cs b/SMBLibrary/SMB2/Commands/CloseRequest.cs new file mode 100644 index 0000000..9f4e960 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/CloseRequest.cs @@ -0,0 +1,54 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 CLOSE Request + /// + public class CloseRequest : SMB2Command + { + public const int DeclaredSize = 24; + + public ushort StructureSize; + public CloseFlags Flags; + public uint Reserved; + public FileID FileId; + + public CloseRequest() : base(SMB2CommandName.Close) + { + StructureSize = DeclaredSize; + } + + public CloseRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Flags = (CloseFlags)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + Reserved = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + FileId = new FileID(buffer, offset + SMB2Header.Length + 8); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, (ushort)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, Reserved); + FileId.WriteBytes(buffer, offset + 8); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/CloseResponse.cs b/SMBLibrary/SMB2/Commands/CloseResponse.cs new file mode 100644 index 0000000..72158e8 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/CloseResponse.cs @@ -0,0 +1,73 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 CLOSE Response + /// + public class CloseResponse : SMB2Command + { + public const int DeclaredSize = 60; + + public ushort StructureSize; + public CloseFlags Flags; + public uint Reserved; + public DateTime? CreationTime; + public DateTime? LastAccessTime; + public DateTime? LastWriteTime; + public DateTime? ChangeTime; + public ulong AllocationSize; + public ulong EndofFile; + public FileAttributes FileAttributes; + + public CloseResponse() : base(SMB2CommandName.Close) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public CloseResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Flags = (CloseFlags)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + Reserved = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + CreationTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 8); + LastAccessTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 16); + LastWriteTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 24); + ChangeTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 32); + AllocationSize = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 40); + EndofFile = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 48); + FileAttributes = (FileAttributes)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 56); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, (ushort)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, Reserved); + FileTimeHelper.WriteFileTime(buffer, offset + 8, CreationTime); + FileTimeHelper.WriteFileTime(buffer, offset + 16, LastAccessTime); + FileTimeHelper.WriteFileTime(buffer, offset + 24, LastWriteTime); + FileTimeHelper.WriteFileTime(buffer, offset + 32, ChangeTime); + LittleEndianWriter.WriteUInt64(buffer, offset + 40, AllocationSize); + LittleEndianWriter.WriteUInt64(buffer, offset + 48, EndofFile); + LittleEndianWriter.WriteUInt32(buffer, offset + 56, (uint)FileAttributes); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/CreateRequest.cs b/SMBLibrary/SMB2/Commands/CreateRequest.cs new file mode 100644 index 0000000..5537b36 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/CreateRequest.cs @@ -0,0 +1,119 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 LOGOFF Request + /// + public class CreateRequest : SMB2Command + { + public const int FixedLength = 56; + public const int DeclaredSize = 57; + + public ushort StructureSize; + public byte SecurityFlags; // Reserved + public OplockLevel RequestedOplockLevel; + public ImpersonationLevel ImpersonationLevel; + public ulong SmbCreateFlags; + public ulong Reserved; + public AccessMask DesiredAccess; + public FileAttributes FileAttributes; + public ShareAccess ShareAccess; + public CreateDisposition CreateDisposition; + public CreateOptions CreateOptions; + private ushort NameOffset; + private ushort NameLength; + public string Name; + private uint CreateContextsOffsets; + private uint CreateContextsLength; + public List CreateContexts = new List(); + + public CreateRequest() : base(SMB2CommandName.Create) + { + StructureSize = DeclaredSize; + } + + public CreateRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + SecurityFlags = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + RequestedOplockLevel = (OplockLevel)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + ImpersonationLevel = (ImpersonationLevel)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + SmbCreateFlags = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 8); + Reserved = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 16); + DesiredAccess = new AccessMask(buffer, offset + SMB2Header.Length + 24); + FileAttributes = (FileAttributes)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 28); + ShareAccess = (ShareAccess)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 32); + CreateDisposition = (CreateDisposition)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 36); + CreateOptions = (CreateOptions)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 40); + NameOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 44); + NameLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 46); + CreateContextsOffsets = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 48); + CreateContextsLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 52); + Name = ByteReader.ReadUTF16String(buffer, offset + NameOffset, NameLength / 2); + if (CreateContextsLength > 0) + { + CreateContexts = CreateContext.ReadCreateContextList(buffer, (int)CreateContextsOffsets); + } + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + NameOffset = 0; + NameLength = (ushort)(Name.Length * 2); + if (Name.Length > 0) + { + NameOffset = SMB2Header.Length + FixedLength; + } + CreateContextsOffsets = 0; + CreateContextsLength = 0; + int paddedNameLength = (int)Math.Ceiling((double)(Name.Length * 2) / 8) * 8; + if (CreateContexts.Count > 0) + { + CreateContextsOffsets = (uint)(SMB2Header.Length + 56 + paddedNameLength); + CreateContextsLength = (uint)CreateContext.GetCreateContextListLength(CreateContexts); + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, SecurityFlags); + ByteWriter.WriteByte(buffer, offset + 3, (byte)RequestedOplockLevel); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, (uint)ImpersonationLevel); + LittleEndianWriter.WriteUInt64(buffer, offset + 8, (ulong)SmbCreateFlags); + LittleEndianWriter.WriteUInt64(buffer, offset + 16, (ulong)Reserved); + DesiredAccess.WriteBytes(buffer, offset + 24); + LittleEndianWriter.WriteUInt32(buffer, offset + 28, (uint)FileAttributes); + LittleEndianWriter.WriteUInt32(buffer, offset + 32, (uint)ShareAccess); + LittleEndianWriter.WriteUInt32(buffer, offset + 36, (uint)CreateDisposition); + LittleEndianWriter.WriteUInt32(buffer, offset + 40, (uint)CreateOptions); + LittleEndianWriter.WriteUInt16(buffer, offset + 44, NameOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 46, NameLength); + LittleEndianWriter.WriteUInt32(buffer, offset + 48, CreateContextsOffsets); + LittleEndianWriter.WriteUInt32(buffer, offset + 52, CreateContextsLength); + ByteWriter.WriteUTF16String(buffer, offset + 56, Name); + CreateContext.WriteCreateContextList(buffer, offset + 56 + paddedNameLength, CreateContexts); + } + + public override int CommandLength + { + get + { + if (CreateContexts.Count == 0) + { + return FixedLength + Name.Length * 2; + } + else + { + int paddedNameLength = (int)Math.Ceiling((double)(Name.Length * 2) / 8) * 8; + return FixedLength + paddedNameLength + CreateContext.GetCreateContextListLength(CreateContexts); + } + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/CreateResponse.cs b/SMBLibrary/SMB2/Commands/CreateResponse.cs new file mode 100644 index 0000000..6038d69 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/CreateResponse.cs @@ -0,0 +1,98 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 CREATE Response + /// + public class CreateResponse : SMB2Command + { + public const int DeclaredSize = 89; + + public ushort StructureSize; + public OplockLevel OplockLevel; + public CreateResponseFlags Flags; + public CreateAction CreateAction; + public DateTime? CreationTime; + public DateTime? LastAccessTime; + public DateTime? LastWriteTime; + public DateTime? ChangeTime; + public ulong AllocationSize; + public ulong EndofFile; + public FileAttributes FileAttributes; + public uint Reserved2; + public FileID FileId; + private uint CreateContextsOffsets; + private uint CreateContextsLength; + public List CreateContexts = new List(); + + public CreateResponse() : base(SMB2CommandName.Create) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public CreateResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + OplockLevel = (OplockLevel)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + Flags = (CreateResponseFlags)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + CreateAction = (CreateAction)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + CreationTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 8); + LastAccessTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 16); + LastWriteTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 24); + ChangeTime = FileTimeHelper.ReadNullableFileTime(buffer, offset + SMB2Header.Length + 32); + AllocationSize = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 40); + EndofFile = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 48); + FileAttributes = (FileAttributes)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 56); + Reserved2 = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 60); + FileId = new FileID(buffer, offset + SMB2Header.Length + 64); + CreateContextsOffsets = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 80); + CreateContextsLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 84); + if (CreateContextsLength > 0) + { + CreateContexts = CreateContext.ReadCreateContextList(buffer, offset + (int)CreateContextsOffsets); + } + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, (byte)OplockLevel); + ByteWriter.WriteByte(buffer, offset + 3, (byte)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, (uint)CreateAction); + FileTimeHelper.WriteFileTime(buffer, offset + 8, CreationTime); + FileTimeHelper.WriteFileTime(buffer, offset + 16, LastAccessTime); + FileTimeHelper.WriteFileTime(buffer, offset + 24, LastWriteTime); + FileTimeHelper.WriteFileTime(buffer, offset + 32, ChangeTime); + LittleEndianWriter.WriteUInt64(buffer, offset + 40, AllocationSize); + LittleEndianWriter.WriteUInt64(buffer, offset + 48, EndofFile); + LittleEndianWriter.WriteUInt32(buffer, offset + 56, (uint)FileAttributes); + LittleEndianWriter.WriteUInt32(buffer, offset + 60, Reserved2); + FileId.WriteBytes(buffer, offset + 64); + CreateContextsOffsets = 0; + CreateContextsLength = (uint)CreateContext.GetCreateContextListLength(CreateContexts); + if (CreateContexts.Count > 0) + { + CreateContextsOffsets = SMB2Header.Length + 88; + CreateContext.WriteCreateContextList(buffer, 88, CreateContexts); + } + } + + public override int CommandLength + { + get + { + return 88 + CreateContext.GetCreateContextListLength(CreateContexts); + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/EchoRequest.cs b/SMBLibrary/SMB2/Commands/EchoRequest.cs new file mode 100644 index 0000000..80b23a1 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/EchoRequest.cs @@ -0,0 +1,48 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 ECHO Request + /// + public class EchoRequest : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public EchoRequest() : base(SMB2CommandName.Echo) + { + StructureSize = DeclaredSize; + } + + public EchoRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/EchoResponse.cs b/SMBLibrary/SMB2/Commands/EchoResponse.cs new file mode 100644 index 0000000..ef3729d --- /dev/null +++ b/SMBLibrary/SMB2/Commands/EchoResponse.cs @@ -0,0 +1,49 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 ECHO Response + /// + public class EchoResponse : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public EchoResponse() : base(SMB2CommandName.Echo) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public EchoResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/ErrorResponse.cs b/SMBLibrary/SMB2/Commands/ErrorResponse.cs new file mode 100644 index 0000000..00c41f0 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/ErrorResponse.cs @@ -0,0 +1,77 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 ERROR Response + /// + public class ErrorResponse : SMB2Command + { + public const int FixedSize = 8; + public const int DeclaredSize = 9; + + public ushort StructureSize; + public byte ErrorContextCount; + public byte Reserved; + private uint ByteCount; + public byte[] ErrorData = new byte[0]; + + public ErrorResponse(SMB2CommandName commandName) : base(commandName) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public ErrorResponse(SMB2CommandName commandName, NTStatus status) : base(commandName) + { + Header.IsResponse = true; + Header.Status = status; + StructureSize = DeclaredSize; + } + + public ErrorResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + ErrorContextCount = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + Reserved = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + ByteCount = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + ErrorData = ByteReader.ReadBytes(buffer, offset + SMB2Header.Length + 8, (int)ByteCount); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + ByteCount = (uint)ErrorData.Length; + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, ErrorContextCount); + ByteWriter.WriteByte(buffer, offset + 3, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, ByteCount); + if (ErrorData.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + 8, ErrorData); + } + else + { + // If the ByteCount field is zero then the server MUST supply an ErrorData field that is one byte in length, and SHOULD set that byte to zero + ByteWriter.WriteBytes(buffer, offset + 8, new byte[1]); + } + + } + + public override int CommandLength + { + get + { + // If the ByteCount field is zero then the server MUST supply an ErrorData field that is one byte in length + return FixedSize + Math.Max(ErrorData.Length, 1); + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/FlushRequest.cs b/SMBLibrary/SMB2/Commands/FlushRequest.cs new file mode 100644 index 0000000..a83fa0f --- /dev/null +++ b/SMBLibrary/SMB2/Commands/FlushRequest.cs @@ -0,0 +1,54 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 FLUSH Request + /// + public class FlushRequest : SMB2Command + { + public const int DeclaredSize = 24; + + public ushort StructureSize; + public ushort Reserved1; + public uint Reserved2; + public FileID FileId; + + public FlushRequest() : base(SMB2CommandName.Flush) + { + StructureSize = DeclaredSize; + } + + public FlushRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved1 = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + Reserved2 = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + FileId = new FileID(buffer, offset + SMB2Header.Length + 8); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved1); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, Reserved2); + FileId.WriteBytes(buffer, offset + 8); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/FlushResponse.cs b/SMBLibrary/SMB2/Commands/FlushResponse.cs new file mode 100644 index 0000000..765ddcf --- /dev/null +++ b/SMBLibrary/SMB2/Commands/FlushResponse.cs @@ -0,0 +1,49 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 FLUSH Response + /// + public class FlushResponse : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public FlushResponse() : base(SMB2CommandName.Flush) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public FlushResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/IOCtlRequest.cs b/SMBLibrary/SMB2/Commands/IOCtlRequest.cs new file mode 100644 index 0000000..ccfd210 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/IOCtlRequest.cs @@ -0,0 +1,122 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 IOCTL Request + /// + public class IOCtlRequest : SMB2Command + { + public const int FixedLength = 56; + public const int DeclaredSize = 57; + + public ushort StructureSize; + public ushort Reserved; + public uint CtlCode; + public FileID FileId; + private uint InputOffset; + private uint InputCount; + public uint MaxInputResponse; + private uint OutputOffset; + private uint OutputCount; + public uint MaxOutputResponse; + public IOCtlRequestFlags Flags; + public uint Reserved2; + public byte[] Input = new byte[0]; + public byte[] Output = new byte[0]; + + public IOCtlRequest() : base(SMB2CommandName.IOCtl) + { + StructureSize = DeclaredSize; + } + + public IOCtlRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + CtlCode = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + FileId = new FileID(buffer, offset + SMB2Header.Length + 8); + InputOffset = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 24); + InputCount = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 28); + MaxInputResponse = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 32); + OutputOffset = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 36); + OutputCount = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 40); + MaxOutputResponse = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 44); + Flags = (IOCtlRequestFlags)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 48); + Reserved2 = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 52); + Input = ByteReader.ReadBytes(buffer, offset + (int)InputOffset, (int)InputCount); + Output = ByteReader.ReadBytes(buffer, offset + (int)OutputOffset, (int)OutputCount); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + InputOffset = 0; + InputCount = (uint)Input.Length; + OutputOffset = 0; + OutputCount = (uint)Output.Length; + if (Input.Length > 0) + { + InputOffset = SMB2Header.Length + FixedLength; + } + if (Output.Length > 0) + { + OutputOffset = InputOffset + (uint)Input.Length; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, CtlCode); + FileId.WriteBytes(buffer, offset + 8); + LittleEndianWriter.WriteUInt32(buffer, offset + 24, InputOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 28, InputCount); + LittleEndianWriter.WriteUInt32(buffer, offset + 32, MaxInputResponse); + LittleEndianWriter.WriteUInt32(buffer, offset + 36, OutputOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 40, OutputCount); + LittleEndianWriter.WriteUInt32(buffer, offset + 44, MaxOutputResponse); + LittleEndianWriter.WriteUInt32(buffer, offset + 48, (uint)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 52, Reserved2); + if (Input.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedLength, Input); + } + if (Output.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedLength + Input.Length, Output); + } + } + + public bool IsFSCtl + { + get + { + return (Flags & IOCtlRequestFlags.IsFSCtl) > 0; + } + set + { + if (value) + { + Flags |= IOCtlRequestFlags.IsFSCtl; + } + else + { + Flags &= ~IOCtlRequestFlags.IsFSCtl; + } + } + } + + public override int CommandLength + { + get + { + return FixedLength + Input.Length + Output.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/IOCtlResponse.cs b/SMBLibrary/SMB2/Commands/IOCtlResponse.cs new file mode 100644 index 0000000..886b14e --- /dev/null +++ b/SMBLibrary/SMB2/Commands/IOCtlResponse.cs @@ -0,0 +1,101 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 IOCTL Request + /// + public class IOCtlResponse : SMB2Command + { + public const int FixedLength = 48; + public const int DeclaredSize = 49; + + public ushort StructureSize; + public ushort Reserved; + public uint CtlCode; + public FileID FileId; + private uint InputOffset; + private uint InputCount; + private uint OutputOffset; + private uint OutputCount; + public uint Flags; + public uint Reserved2; + public byte[] Input = new byte[0]; + public byte[] Output = new byte[0]; + + public IOCtlResponse() : base(SMB2CommandName.IOCtl) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public IOCtlResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + CtlCode = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + FileId = new FileID(buffer, offset + SMB2Header.Length + 8); + InputOffset = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 24); + InputCount = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 28); + OutputOffset = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 32); + OutputCount = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 36); + Flags = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 40); + Reserved2 = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 44); + Input = ByteReader.ReadBytes(buffer, offset + (int)InputOffset, (int)InputCount); + Output = ByteReader.ReadBytes(buffer, offset + (int)OutputOffset, (int)OutputCount); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + InputOffset = 0; + InputCount = (uint)Input.Length; + OutputOffset = 0; + OutputCount = (uint)Output.Length; + if (Input.Length > 0) + { + InputOffset = SMB2Header.Length + FixedLength; + } + // MS-SMB2: the output offset MUST be set to InputOffset + InputCount rounded up to a multiple of 8 + int paddedInputLength = (int)Math.Ceiling((double)Input.Length / 8) * 8; + if (Output.Length > 0) + { + OutputOffset = SMB2Header.Length + FixedLength + (uint)paddedInputLength; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, CtlCode); + FileId.WriteBytes(buffer, offset + 8); + LittleEndianWriter.WriteUInt32(buffer, offset + 24, InputOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 28, InputCount); + LittleEndianWriter.WriteUInt32(buffer, offset + 32, OutputOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 36, OutputCount); + LittleEndianWriter.WriteUInt32(buffer, offset + 40, Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 44, Reserved2); + if (Input.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedLength, Input); + } + if (Output.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedLength + paddedInputLength, Output); + } + } + + public override int CommandLength + { + get + { + int paddedInputLength = (int)Math.Ceiling((double)Input.Length / 8) * 8; + return FixedLength + paddedInputLength + Output.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/LockRequest.cs b/SMBLibrary/SMB2/Commands/LockRequest.cs new file mode 100644 index 0000000..5a5f2e0 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/LockRequest.cs @@ -0,0 +1,60 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 LOCK Request + /// + public class LockRequest : SMB2Command + { + public const int DeclaredSize = 48; + + public ushort StructureSize; + public ushort LockCount; + public byte LSN; // 4 bits + public uint LockSequenceIndex; // 28 bits + public FileID FileId; + public List Locks; + + public LockRequest() : base(SMB2CommandName.Lock) + { + StructureSize = DeclaredSize; + } + + public LockRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + LockCount = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + uint temp = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + LSN = (byte)(temp >> 28); + LockSequenceIndex = (temp & 0x0FFFFFFF); + FileId = new FileID(buffer, offset + SMB2Header.Length + 8); + Locks = LockElement.ReadLockList(buffer, offset + SMB2Header.Length + 24, (int)LockCount); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, LockCount); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, (uint)(LSN & 0x0F) << 28 | (uint)(LockSequenceIndex & 0x0FFFFFFF)); + FileId.WriteBytes(buffer, offset + 8); + LockElement.WriteLockList(buffer, offset + 24, Locks); + } + + public override int CommandLength + { + get + { + return 48 + Locks.Count * LockElement.StructureLength; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/LockResponse.cs b/SMBLibrary/SMB2/Commands/LockResponse.cs new file mode 100644 index 0000000..db025e4 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/LockResponse.cs @@ -0,0 +1,49 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 LOCK Response + /// + public class LockResponse : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public LockResponse() : base(SMB2CommandName.Lock) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public LockResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/LogoffRequest.cs b/SMBLibrary/SMB2/Commands/LogoffRequest.cs new file mode 100644 index 0000000..fa22433 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/LogoffRequest.cs @@ -0,0 +1,48 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 LOGOFF Request + /// + public class LogoffRequest : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public LogoffRequest() : base(SMB2CommandName.Logoff) + { + StructureSize = 4; + } + + public LogoffRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/LogoffResponse.cs b/SMBLibrary/SMB2/Commands/LogoffResponse.cs new file mode 100644 index 0000000..8855cc3 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/LogoffResponse.cs @@ -0,0 +1,49 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 LOGOFF Response + /// + public class LogoffResponse : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public LogoffResponse() : base(SMB2CommandName.Logoff) + { + Header.IsResponse = true; + StructureSize = 4; + } + + public LogoffResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/NegotiateRequest.cs b/SMBLibrary/SMB2/Commands/NegotiateRequest.cs new file mode 100644 index 0000000..254a7c9 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/NegotiateRequest.cs @@ -0,0 +1,76 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 NEGOTIATE Request + /// + public class NegotiateRequest : SMB2Command + { + public const int DeclaredSize = 36; + + public ushort StructureSize; + private ushort DialectCount; + public SecurityMode SecurityMode; + public ushort Reserved; + public ServerCapabilities Capabilities; + public Guid ClientGuid; + public DateTime ClientStartTime; + public List Dialects = new List(); + + public NegotiateRequest() : base(SMB2CommandName.Negotiate) + { + StructureSize = DeclaredSize; + } + + public NegotiateRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + DialectCount = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + SecurityMode = (SecurityMode)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 4); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 6); + Capabilities = (ServerCapabilities)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 8); + ClientGuid = LittleEndianConverter.ToGuid(buffer, offset + SMB2Header.Length + 12); + ClientStartTime = DateTime.FromFileTimeUtc(LittleEndianConverter.ToInt64(buffer, offset + SMB2Header.Length + 28)); + + for (int index = 0; index < DialectCount; index++) + { + SMB2Dialect dialect = (SMB2Dialect)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 36 + index * 2); + Dialects.Add(dialect); + } + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, DialectCount); + LittleEndianWriter.WriteUInt16(buffer, offset + 4, (ushort)SecurityMode); + LittleEndianWriter.WriteUInt16(buffer, offset + 6, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 8, (uint)Capabilities); + LittleEndianWriter.WriteGuidBytes(buffer, offset + 12, ClientGuid); + LittleEndianWriter.WriteInt64(buffer, offset + 28, ClientStartTime.ToFileTimeUtc()); + + for (int index = 0; index < Dialects.Count; index++) + { + SMB2Dialect dialect = Dialects[index]; + LittleEndianWriter.WriteUInt16(buffer, offset + 36 + index * 2, (ushort)dialect); + } + } + + public override int CommandLength + { + get + { + return 36 + Dialects.Count * 2; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/NegotiateResponse.cs b/SMBLibrary/SMB2/Commands/NegotiateResponse.cs new file mode 100644 index 0000000..b5ab7ca --- /dev/null +++ b/SMBLibrary/SMB2/Commands/NegotiateResponse.cs @@ -0,0 +1,114 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 NEGOTIATE Response + /// + public class NegotiateResponse : SMB2Command + { + public const int FixedSize = 64; + public const int DeclaredSize = 65; + + public ushort StructureSize; + public SecurityMode SecurityMode; + public SMB2Dialect DialectRevision; + private ushort NegotiateContextCount; + public Guid ServerGuid; + public ServerCapabilities Capabilities; + public uint MaxTransactSize; + public uint MaxReadSize; + public uint MaxWriteSize; + public DateTime SystemTime; + public DateTime ServerStartTime; + private ushort SecurityBufferOffset; + private ushort SecurityBufferLength; + private uint NegotiateContextOffset; + public byte[] SecurityBuffer = new byte[0]; + public List NegotiateContextList = new List(); + + public NegotiateResponse() : base(SMB2CommandName.Negotiate) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public NegotiateResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + SecurityMode = (SecurityMode)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + DialectRevision = (SMB2Dialect)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 4); + NegotiateContextCount = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 6); + ServerGuid = LittleEndianConverter.ToGuid(buffer, offset + SMB2Header.Length + 8); + Capabilities = (ServerCapabilities)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 24); + MaxTransactSize = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 28); + MaxReadSize = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 32); + MaxWriteSize = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 36); + SystemTime = DateTime.FromFileTimeUtc(LittleEndianConverter.ToInt64(buffer, offset + SMB2Header.Length + 40)); + ServerStartTime = DateTime.FromFileTimeUtc(LittleEndianConverter.ToInt64(buffer, offset + SMB2Header.Length + 48)); + SecurityBufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 56); + SecurityBufferLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 58); + NegotiateContextOffset = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 60); + SecurityBuffer = ByteReader.ReadBytes(buffer, offset + SecurityBufferOffset, SecurityBufferLength); + NegotiateContextList = NegotiateContext.ReadNegotiateContextList(buffer, (int)NegotiateContextOffset, NegotiateContextCount); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + SecurityBufferOffset = 0; + SecurityBufferLength = (ushort)SecurityBuffer.Length; + int paddedSecurityBufferLength = (int)Math.Ceiling((double)SecurityBufferLength / 8) * 8; + if (SecurityBuffer.Length > 0) + { + SecurityBufferOffset = SMB2Header.Length + FixedSize; + } + NegotiateContextOffset = 0; + NegotiateContextCount = (ushort)NegotiateContextList.Count; + if (NegotiateContextList.Count > 0) + { + // NegotiateContextList must be 8-byte aligned + NegotiateContextOffset = (uint)(SMB2Header.Length + FixedSize + paddedSecurityBufferLength); + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, (ushort)SecurityMode); + LittleEndianWriter.WriteUInt16(buffer, offset + 4, (ushort)DialectRevision); + LittleEndianWriter.WriteUInt16(buffer, offset + 6, NegotiateContextCount); + LittleEndianWriter.WriteGuidBytes(buffer, offset + 8, ServerGuid); + LittleEndianWriter.WriteUInt32(buffer, offset + 24, (uint)Capabilities); + LittleEndianWriter.WriteUInt32(buffer, offset + 28, MaxTransactSize); + LittleEndianWriter.WriteUInt32(buffer, offset + 32, MaxReadSize); + LittleEndianWriter.WriteUInt32(buffer, offset + 36, MaxWriteSize); + LittleEndianWriter.WriteInt64(buffer, offset + 40, SystemTime.ToFileTimeUtc()); + LittleEndianWriter.WriteInt64(buffer, offset + 48, ServerStartTime.ToFileTimeUtc()); + LittleEndianWriter.WriteUInt16(buffer, offset + 56, SecurityBufferOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 58, SecurityBufferLength); + LittleEndianWriter.WriteUInt32(buffer, offset + 60, NegotiateContextOffset); + ByteWriter.WriteBytes(buffer, offset + FixedSize, SecurityBuffer); + NegotiateContext.WriteNegotiateContextList(buffer, offset + FixedSize + paddedSecurityBufferLength, NegotiateContextList); + } + + public override int CommandLength + { + get + { + if (NegotiateContextList.Count == 0) + { + return FixedSize + SecurityBuffer.Length; + } + else + { + int paddedSecurityBufferLength = (int)Math.Ceiling((double)SecurityBufferLength / 8) * 8; + return FixedSize + paddedSecurityBufferLength + NegotiateContext.GetNegotiateContextListLength(NegotiateContextList); + } + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/QueryDirectoryRequest.cs b/SMBLibrary/SMB2/Commands/QueryDirectoryRequest.cs new file mode 100644 index 0000000..113dd68 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/QueryDirectoryRequest.cs @@ -0,0 +1,133 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 QUERY_DIRECTORY Request + /// + public class QueryDirectoryRequest : SMB2Command + { + public const int FixedLength = 32; + public const int DeclaredSize = 33; + + public ushort StructureSize; + public FileInformationClass FileInformationClass; + public QueryDirectoryFlags Flags; + public uint FileIndex; + public FileID FileId; + private ushort FileNameOffset; + private ushort FileNameLength; + public uint OutputBufferLength; + public string FileName = String.Empty; + + public QueryDirectoryRequest() : base(SMB2CommandName.QueryDirectory) + { + StructureSize = DeclaredSize; + } + + public QueryDirectoryRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + FileInformationClass = (FileInformationClass)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + Flags = (QueryDirectoryFlags)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + FileIndex = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + FileId = new FileID(buffer, offset + SMB2Header.Length + 8); + FileNameOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 24); + FileNameLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 26); + OutputBufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 28); + FileName = ByteReader.ReadUTF16String(buffer, offset + FileNameOffset, FileNameLength / 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + FileNameOffset = 0; + FileNameLength = (ushort)(FileName.Length * 2); + if (FileName.Length > 0) + { + FileNameOffset = SMB2Header.Length + FixedLength; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, (byte)FileInformationClass); + ByteWriter.WriteByte(buffer, offset + 3, (byte)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, FileIndex); + FileId.WriteBytes(buffer, offset + 8); + LittleEndianWriter.WriteUInt16(buffer, offset + 24, FileNameOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 26, FileNameLength); + LittleEndianWriter.WriteUInt32(buffer, offset + 28, OutputBufferLength); + ByteWriter.WriteUTF16String(buffer, offset + 32, FileName); + } + + public bool Restart + { + get + { + return ((this.Flags & QueryDirectoryFlags.SMB2_RESTART_SCANS) > 0); + } + set + { + if (value) + { + Flags |= QueryDirectoryFlags.SMB2_RESTART_SCANS; + } + else + { + Flags &= ~QueryDirectoryFlags.SMB2_RESTART_SCANS; + } + } + } + + public bool ReturnSingleEntry + { + get + { + return ((this.Flags & QueryDirectoryFlags.SMB2_RETURN_SINGLE_ENTRY) > 0); + } + set + { + if (value) + { + Flags |= QueryDirectoryFlags.SMB2_RETURN_SINGLE_ENTRY; + } + else + { + Flags &= ~QueryDirectoryFlags.SMB2_RETURN_SINGLE_ENTRY; + } + } + } + + public bool Reopen + { + get + { + return ((this.Flags & QueryDirectoryFlags.SMB2_REOPEN) > 0); + } + set + { + if (value) + { + Flags |= QueryDirectoryFlags.SMB2_REOPEN; + } + else + { + Flags &= ~QueryDirectoryFlags.SMB2_REOPEN; + } + } + } + + public override int CommandLength + { + get + { + return FixedLength + FileName.Length * 2; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/QueryDirectoryResponse.cs b/SMBLibrary/SMB2/Commands/QueryDirectoryResponse.cs new file mode 100644 index 0000000..8f7569a --- /dev/null +++ b/SMBLibrary/SMB2/Commands/QueryDirectoryResponse.cs @@ -0,0 +1,79 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 QUERY_DIRECTORY Response + /// + public class QueryDirectoryResponse : SMB2Command + { + public const int FixedLength = 8; + public const int DeclaredSize = 9; + + public ushort StructureSize; + private ushort OutputBufferOffset; + private uint OutputBufferLength; + public byte[] OutputBuffer = new byte[0]; + + public QueryDirectoryResponse() : base(SMB2CommandName.QueryDirectory) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public QueryDirectoryResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + OutputBufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + OutputBufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + OutputBuffer = ByteReader.ReadBytes(buffer, offset + (int)OutputBufferOffset, (int)OutputBufferLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + OutputBufferOffset = 0; + OutputBufferLength = (uint)OutputBuffer.Length; + if (OutputBuffer.Length > 0) + { + OutputBufferOffset = SMB2Header.Length + FixedLength; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, OutputBufferOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, OutputBufferLength); + ByteWriter.WriteBytes(buffer, offset + FixedLength, OutputBuffer); + } + + public List GetFileInformationList(FileInformationClass fileInformationClass) + { + if (OutputBuffer.Length > 0) + { + return QueryDirectoryFileInformation.ReadFileInformationList(OutputBuffer, 0, fileInformationClass); + } + else + { + return new List(); + } + } + + public void SetFileInformationList(List fileInformationList) + { + OutputBuffer = QueryDirectoryFileInformation.GetBytes(fileInformationList); + } + + public override int CommandLength + { + get + { + return FixedLength + OutputBuffer.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/QueryInfoRequest.cs b/SMBLibrary/SMB2/Commands/QueryInfoRequest.cs new file mode 100644 index 0000000..459d1dd --- /dev/null +++ b/SMBLibrary/SMB2/Commands/QueryInfoRequest.cs @@ -0,0 +1,111 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 QUERY_INFO Request + /// + public class QueryInfoRequest : SMB2Command + { + public const int FixedSize = 40; + public const int DeclaredSize = 41; + + public ushort StructureSize; + public InfoType InfoType; + private byte FileInfoClass; + public uint OutputBufferLength; + private ushort InputBufferOffset; + public ushort Reserved; + private uint InputBufferLength; + public uint AdditionalInformation; + public uint Flags; + public FileID FileId; + public byte[] InputBuffer = new byte[0]; + + public QueryInfoRequest() : base(SMB2CommandName.QueryInfo) + { + StructureSize = DeclaredSize; + } + + public QueryInfoRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + InfoType = (InfoType)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + FileInfoClass = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + OutputBufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + InputBufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 8); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 10); + InputBufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 12); + AdditionalInformation = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 16); + Flags = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 20); + FileId = new FileID(buffer, offset + SMB2Header.Length + 24); + InputBuffer = ByteReader.ReadBytes(buffer, offset + InputBufferOffset, (int)InputBufferLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + InputBufferOffset = 0; + InputBufferLength = (uint)InputBuffer.Length; + if (InputBuffer.Length > 0) + { + InputBufferOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, (byte)InfoType); + ByteWriter.WriteByte(buffer, offset + 3, FileInfoClass); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, OutputBufferLength); + LittleEndianWriter.WriteUInt16(buffer, offset + 8, InputBufferOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 10, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 12, InputBufferLength); + LittleEndianWriter.WriteUInt32(buffer, offset + 16, AdditionalInformation); + LittleEndianWriter.WriteUInt32(buffer, offset + 20, Flags); + FileId.WriteBytes(buffer, offset + 24); + ByteWriter.WriteBytes(buffer, offset + FixedSize, InputBuffer); + } + + public FileInformationClass FileInformationClass + { + get + { + return (FileInformationClass)FileInfoClass; + } + set + { + FileInfoClass = (byte)value; + } + } + + public FileSystemInformationClass FileSystemInformationClass + { + get + { + return (FileSystemInformationClass)FileInfoClass; + } + set + { + FileInfoClass = (byte)value; + } + } + + public void SetFileInformation(FileInformation fileInformation) + { + InputBuffer = fileInformation.GetBytes(); + } + + public override int CommandLength + { + get + { + return FixedSize + InputBuffer.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/QueryInfoResponse.cs b/SMBLibrary/SMB2/Commands/QueryInfoResponse.cs new file mode 100644 index 0000000..0d1f0ad --- /dev/null +++ b/SMBLibrary/SMB2/Commands/QueryInfoResponse.cs @@ -0,0 +1,72 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 QUERY_INFO Response + /// + public class QueryInfoResponse : SMB2Command + { + public const int FixedSize = 8; + public const int DeclaredSize = 9; + + public ushort StructureSize; + private ushort OutputBufferOffset; + private uint OutputBufferLength; + public byte[] OutputBuffer = new byte[0]; + + public QueryInfoResponse() : base(SMB2CommandName.QueryInfo) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public QueryInfoResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + OutputBufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + OutputBufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + OutputBuffer = ByteReader.ReadBytes(buffer, offset + OutputBufferOffset, (int)OutputBufferLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + OutputBufferOffset = 0; + OutputBufferLength = (uint)OutputBuffer.Length; + if (OutputBuffer.Length > 0) + { + OutputBufferOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, OutputBufferOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, OutputBufferLength); + ByteWriter.WriteBytes(buffer, offset + FixedSize, OutputBuffer); + } + + public void SetFileInformation(FileInformation fileInformation) + { + OutputBuffer = fileInformation.GetBytes(); + } + + public void SetFileSystemInformation(FileSystemInformation fileSystemInformation) + { + OutputBuffer = fileSystemInformation.GetBytes(); + } + + public override int CommandLength + { + get + { + return FixedSize + OutputBuffer.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/ReadRequest.cs b/SMBLibrary/SMB2/Commands/ReadRequest.cs new file mode 100644 index 0000000..cdf4d86 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/ReadRequest.cs @@ -0,0 +1,97 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 READ Request + /// + public class ReadRequest : SMB2Command + { + public const int FixedSize = 48; + public const int DeclaredSize = 49; + + public ushort StructureSize; + public byte Padding; + public ReadFlags Flags; + public uint ReadLength; + public ulong Offset; + public FileID FileId; + public uint MinimumCount; + public uint Channel; + public uint RemainingBytes; + private ushort ReadChannelInfoOffset; + private ushort ReadChannelInfoLength; + public byte[] ReadChannelInfo = new byte[0]; + + public ReadRequest() : base(SMB2CommandName.Read) + { + StructureSize = DeclaredSize; + } + + public ReadRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Padding = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + Flags = (ReadFlags)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + ReadLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + Offset = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 8); + FileId = new FileID(buffer, offset + SMB2Header.Length + 16); + MinimumCount = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 32); + Channel = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 36); + RemainingBytes = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 40); + ReadChannelInfoOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 44); + ReadChannelInfoLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 46); + if (ReadChannelInfoLength > 0) + { + ReadChannelInfo = ByteReader.ReadBytes(buffer, offset + ReadChannelInfoOffset, ReadChannelInfoLength); + } + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + ReadChannelInfoOffset = 0; + ReadChannelInfoLength = (ushort)ReadChannelInfo.Length; + if (ReadChannelInfo.Length > 0) + { + ReadChannelInfoOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, Padding); + ByteWriter.WriteByte(buffer, offset + 3, (byte)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, ReadLength); + LittleEndianWriter.WriteUInt64(buffer, offset + 8, Offset); + FileId.WriteBytes(buffer, offset + 16); + LittleEndianWriter.WriteUInt32(buffer, offset + 32, MinimumCount); + LittleEndianWriter.WriteUInt32(buffer, offset + 36, Channel); + LittleEndianWriter.WriteUInt32(buffer, offset + 40, RemainingBytes); + LittleEndianWriter.WriteUInt16(buffer, offset + 44, ReadChannelInfoOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 46, ReadChannelInfoLength); + if (ReadChannelInfo.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedSize, ReadChannelInfo); + } + else + { + // The client MUST set one byte of [the buffer] field to 0 + ByteWriter.WriteBytes(buffer, offset + FixedSize, new byte[1]); + } + } + + public override int CommandLength + { + get + { + // The client MUST set one byte of [the buffer] field to 0 + return Math.Max(FixedSize + ReadChannelInfo.Length, DeclaredSize); + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/ReadResponse.cs b/SMBLibrary/SMB2/Commands/ReadResponse.cs new file mode 100644 index 0000000..a97c38f --- /dev/null +++ b/SMBLibrary/SMB2/Commands/ReadResponse.cs @@ -0,0 +1,77 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 READ Response + /// + public class ReadResponse : SMB2Command + { + public const int FixedSize = 16; + public const int DeclaredSize = 17; + + public ushort StructureSize; + private byte DataOffset; + public byte Reserved; + private uint DataLength; + public uint DataRemaining; + public uint Reserved2; + public byte[] Data = new byte[0]; + + public ReadResponse() : base(SMB2CommandName.Read) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public ReadResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + DataOffset = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + Reserved = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + DataLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + DataRemaining = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 8); + Reserved2 = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 12); + if (DataLength > 0) + { + Data = ByteReader.ReadBytes(buffer, offset + DataOffset, (int)DataLength); + } + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + DataOffset = 0; + DataLength = (uint)Data.Length; + if (Data.Length > 0) + { + DataOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, DataOffset); + ByteWriter.WriteByte(buffer, offset + 3, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, DataLength); + LittleEndianWriter.WriteUInt32(buffer, offset + 8, DataRemaining); + LittleEndianWriter.WriteUInt32(buffer, offset + 12, Reserved2); + if (Data.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedSize, Data); + } + } + + public override int CommandLength + { + get + { + return FixedSize + Data.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/SMB2Command.cs b/SMBLibrary/SMB2/Commands/SMB2Command.cs new file mode 100644 index 0000000..33adea7 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/SMB2Command.cs @@ -0,0 +1,157 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + public abstract class SMB2Command + { + public SMB2Header Header; + + public SMB2Command(SMB2CommandName commandName) + { + Header = new SMB2Header(commandName); + } + + public SMB2Command(byte[] buffer, int offset) + { + Header = new SMB2Header(buffer, offset); + } + + public void WriteBytes(byte[] buffer, int offset) + { + Header.WriteBytes(buffer, offset); + WriteCommandBytes(buffer, offset + SMB2Header.Length); + } + + public abstract void WriteCommandBytes(byte[] buffer, int offset); + + public byte[] GetBytes() + { + byte[] buffer = new byte[this.Length]; + WriteBytes(buffer, 0); + return buffer; + } + + public SMB2CommandName CommandName + { + get + { + return Header.Command; + } + } + + public int Length + { + get + { + return SMB2Header.Length + CommandLength; + } + } + + public abstract int CommandLength + { + get; + } + + public static SMB2Command ReadRequest(byte[] buffer, int offset) + { + SMB2CommandName Command = (SMB2CommandName)LittleEndianConverter.ToUInt16(buffer, offset + 12); + switch (Command) + { + case SMB2CommandName.Negotiate: + return new NegotiateRequest(buffer, offset); + case SMB2CommandName.SessionSetup: + return new SessionSetupRequest(buffer, offset); + case SMB2CommandName.Logoff: + return new LogoffRequest(buffer, offset); + case SMB2CommandName.TreeConnect: + return new TreeConnectRequest(buffer, offset); + case SMB2CommandName.TreeDisconnect: + return new TreeDisconnectRequest(buffer, offset); + case SMB2CommandName.Create: + return new CreateRequest(buffer, offset); + case SMB2CommandName.Close: + return new CloseRequest(buffer, offset); + case SMB2CommandName.Flush: + return new FlushRequest(buffer, offset); + case SMB2CommandName.Read: + return new ReadRequest(buffer, offset); + case SMB2CommandName.Write: + return new WriteRequest(buffer, offset); + case SMB2CommandName.Lock: + return new LockRequest(buffer, offset); + case SMB2CommandName.IOCtl: + return new IOCtlRequest(buffer, offset); + case SMB2CommandName.Cancel: + return new CancelRequest(buffer, offset); + case SMB2CommandName.Echo: + return new EchoRequest(buffer, offset); + case SMB2CommandName.QueryDirectory: + return new QueryDirectoryRequest(buffer, offset); + case SMB2CommandName.ChangeNotify: + return new ChangeNotifyRequest(buffer, offset); + case SMB2CommandName.QueryInfo: + return new QueryInfoRequest(buffer, offset); + case SMB2CommandName.SetInfo: + return new SetInfoRequest(buffer, offset); + default: + throw new System.IO.InvalidDataException("Invalid SMB2 command in buffer"); + } + } + + public static List ReadRequestChain(byte[] buffer, int offset) + { + List result = new List(); + SMB2Command command; + do + { + command = ReadRequest(buffer, offset); + result.Add(command); + offset += (int)command.Header.NextCommand; + } + while (command.Header.NextCommand != 0); + return result; + } + + public static byte[] GetCommandChainBytes(List commands) + { + int totalLength = 0; + for (int index = 0; index < commands.Count; index++) + { + // Any subsequent SMB2 header MUST be 8-byte aligned + int length = commands[index].Length; + if (index < commands.Count - 1) + { + int paddedLength = (int)Math.Ceiling((double)length / 8) * 8; + totalLength += paddedLength; + } + else + { + totalLength += length; + } + } + byte[] buffer = new byte[totalLength]; + int offset = 0; + for (int index = 0; index < commands.Count; index++) + { + SMB2Command command = commands[index]; + int commandLength = command.Length; + int paddedLength = (int)Math.Ceiling((double)commandLength / 8) * 8; + if (index < commands.Count - 1) + { + command.Header.NextCommand = (uint)paddedLength; + } + command.WriteBytes(buffer, offset); + offset += paddedLength; + } + return buffer; + } + } +} diff --git a/SMBLibrary/SMB2/Commands/SessionSetupRequest.cs b/SMBLibrary/SMB2/Commands/SessionSetupRequest.cs new file mode 100644 index 0000000..9b6d589 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/SessionSetupRequest.cs @@ -0,0 +1,79 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 SESSION_SETUP Request + /// + public class SessionSetupRequest : SMB2Command + { + public const int FixedSize = 24; + public const int DeclaredSize = 25; + + public ushort StructureSize; + public SessionSetupFlags Flags; + public SecurityMode SecurityMode; + public ServerCapabilities Capabilities; + public uint Channel; + private ushort SecurityBufferOffset; + private ushort SecurityBufferLength; + public ulong PreviousSessionId; + public byte[] SecurityBuffer = new byte[0]; + + public SessionSetupRequest() : base(SMB2CommandName.SessionSetup) + { + StructureSize = DeclaredSize; + } + + public SessionSetupRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Flags = (SessionSetupFlags)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + SecurityMode = (SecurityMode)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + Capabilities = (ServerCapabilities)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + Channel = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 8); + SecurityBufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 12); + SecurityBufferLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 14); + PreviousSessionId = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 16); + if (SecurityBufferLength > 0) + { + SecurityBuffer = ByteReader.ReadBytes(buffer, offset + SecurityBufferOffset, SecurityBufferLength); + } + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + SecurityBufferOffset = 0; + SecurityBufferLength = (ushort)SecurityBuffer.Length; + if (SecurityBuffer.Length > 0) + { + SecurityBufferOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, (byte)Flags); + ByteWriter.WriteByte(buffer, offset + 3, (byte)SecurityMode); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, (uint)Capabilities); + LittleEndianWriter.WriteUInt32(buffer, offset + 8, Channel); + LittleEndianWriter.WriteUInt16(buffer, offset + 12, SecurityBufferOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 14, SecurityBufferLength); + LittleEndianWriter.WriteUInt64(buffer, offset + 16, PreviousSessionId); + ByteWriter.WriteBytes(buffer, offset + FixedSize, SecurityBuffer); + } + + public override int CommandLength + { + get + { + return FixedSize + SecurityBuffer.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/SessionSetupResponse.cs b/SMBLibrary/SMB2/Commands/SessionSetupResponse.cs new file mode 100644 index 0000000..6d49d50 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/SessionSetupResponse.cs @@ -0,0 +1,65 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 SESSION_SETUP Response + /// + public class SessionSetupResponse : SMB2Command + { + public const int FixedSize = 8; + public const int DeclaredSize = 9; + + public ushort StructureSize; + public SessionFlags SessionFlags; + private ushort SecurityBufferOffset; + private ushort SecurityBufferLength; + public byte[] SecurityBuffer = new byte[0]; + + public SessionSetupResponse() : base(SMB2CommandName.SessionSetup) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public SessionSetupResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + SessionFlags = (SessionFlags)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + SecurityBufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 4); + SecurityBufferLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 6); + SecurityBuffer = ByteReader.ReadBytes(buffer, offset + SecurityBufferOffset, SecurityBufferLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + SecurityBufferOffset = 0; + SecurityBufferLength = (ushort)SecurityBuffer.Length; + if (SecurityBuffer.Length > 0) + { + SecurityBufferOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, (ushort)SessionFlags); + LittleEndianWriter.WriteUInt16(buffer, offset + 4, SecurityBufferOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 6, SecurityBufferLength); + ByteWriter.WriteBytes(buffer, offset + 8, SecurityBuffer); + } + + public override int CommandLength + { + get + { + return FixedSize + SecurityBuffer.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/SetInfoRequest.cs b/SMBLibrary/SMB2/Commands/SetInfoRequest.cs new file mode 100644 index 0000000..434240a --- /dev/null +++ b/SMBLibrary/SMB2/Commands/SetInfoRequest.cs @@ -0,0 +1,105 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 SET_INFO Request + /// + public class SetInfoRequest : SMB2Command + { + public const int FixedSize = 32; + public const int DeclaredSize = 33; + + public ushort StructureSize; + public InfoType InfoType; + private byte FileInfoClass; + public uint BufferLength; + private ushort BufferOffset; + public ushort Reserved; + public uint AdditionalInformation; + public FileID FileId; + public byte[] Buffer = new byte[0]; + + public SetInfoRequest() : base(SMB2CommandName.SetInfo) + { + StructureSize = DeclaredSize; + } + + public SetInfoRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + InfoType = (InfoType)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + FileInfoClass = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + BufferLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + BufferOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 8); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 10); + AdditionalInformation = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 12); + FileId = new FileID(buffer, offset + SMB2Header.Length + 16); + Buffer = ByteReader.ReadBytes(buffer, offset + BufferOffset, (int)BufferLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + BufferOffset = 0; + BufferLength = (uint)Buffer.Length; + if (Buffer.Length > 0) + { + BufferOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, (byte)InfoType); + ByteWriter.WriteByte(buffer, offset + 3, FileInfoClass); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, BufferLength); + LittleEndianWriter.WriteUInt16(buffer, offset + 8, BufferOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 10, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 12, AdditionalInformation); + FileId.WriteBytes(buffer, offset + 16); + ByteWriter.WriteBytes(buffer, offset + FixedSize, Buffer); + } + + public FileInformationClass FileInformationClass + { + get + { + return (FileInformationClass)FileInfoClass; + } + set + { + FileInfoClass = (byte)value; + } + } + + public FileSystemInformationClass FileSystemInformationClass + { + get + { + return (FileSystemInformationClass)FileInfoClass; + } + set + { + FileInfoClass = (byte)value; + } + } + + public void SetFileInformation(FileInformation fileInformation) + { + Buffer = fileInformation.GetBytes(); + } + + public override int CommandLength + { + get + { + return FixedSize + Buffer.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/SetInfoResponse.cs b/SMBLibrary/SMB2/Commands/SetInfoResponse.cs new file mode 100644 index 0000000..f7da7e7 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/SetInfoResponse.cs @@ -0,0 +1,46 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 SET_INFO Response + /// + public class SetInfoResponse : SMB2Command + { + public const int DeclaredSize = 2; + + public ushort StructureSize; + + public SetInfoResponse() : base(SMB2CommandName.SetInfo) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public SetInfoResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/TreeConnectRequest.cs b/SMBLibrary/SMB2/Commands/TreeConnectRequest.cs new file mode 100644 index 0000000..29bda1b --- /dev/null +++ b/SMBLibrary/SMB2/Commands/TreeConnectRequest.cs @@ -0,0 +1,70 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 TREE_CONNECT Request + /// + public class TreeConnectRequest : SMB2Command + { + public const int FixedSize = 8; + public const int DeclaredSize = 9; + + public ushort StructureSize; + public ushort Reserved; + private ushort PathOffset; + private ushort PathLength; + public string Path = String.Empty; + + public TreeConnectRequest() : base(SMB2CommandName.TreeConnect) + { + StructureSize = DeclaredSize; + } + + public TreeConnectRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + PathOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 4); + PathLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 6); + if (PathLength > 0) + { + Path = ByteReader.ReadUTF16String(buffer, offset + PathOffset, PathLength / 2); + } + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + PathOffset = 0; + PathLength = (ushort)(Path.Length * 2); + if (Path.Length > 0) + { + PathOffset = SMB2Header.Length + 8; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + LittleEndianWriter.WriteUInt16(buffer, offset + 4, PathOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 6, PathLength); + if (Path.Length > 0) + { + ByteWriter.WriteUTF16String(buffer, offset + 8, Path); + } + } + + public override int CommandLength + { + get + { + return 8 + Path.Length * 2; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/TreeConnectResponse.cs b/SMBLibrary/SMB2/Commands/TreeConnectResponse.cs new file mode 100644 index 0000000..e05ccbc --- /dev/null +++ b/SMBLibrary/SMB2/Commands/TreeConnectResponse.cs @@ -0,0 +1,61 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 TREE_CONNECT Response + /// + public class TreeConnectResponse : SMB2Command + { + public const int DeclaredSize = 16; + + public ushort StructureSize; + public ShareType ShareType; + public byte Reserved; + public ShareFlags ShareFlags; + public ShareCapabilities Capabilities; + public AccessMask MaximalAccess; + + public TreeConnectResponse() : base(SMB2CommandName.TreeConnect) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public TreeConnectResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + ShareType = (ShareType)ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 2); + Reserved = ByteReader.ReadByte(buffer, offset + SMB2Header.Length + 3); + ShareFlags = (ShareFlags)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + Capabilities = (ShareCapabilities)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 8); + MaximalAccess = new AccessMask(buffer, offset + SMB2Header.Length + 12); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + ByteWriter.WriteByte(buffer, offset + 2, (byte)ShareType); + ByteWriter.WriteByte(buffer, offset + 3, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, (uint)ShareFlags); + LittleEndianWriter.WriteUInt32(buffer, offset + 8, (uint)Capabilities); + MaximalAccess.WriteBytes(buffer, offset + 12); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/TreeDisconnectRequest.cs b/SMBLibrary/SMB2/Commands/TreeDisconnectRequest.cs new file mode 100644 index 0000000..8e12619 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/TreeDisconnectRequest.cs @@ -0,0 +1,48 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 TREE_DISCONNECT Request + /// + public class TreeDisconnectRequest : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public TreeDisconnectRequest() : base(SMB2CommandName.TreeDisconnect) + { + StructureSize = DeclaredSize; + } + + public TreeDisconnectRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/TreeDisconnectResponse.cs b/SMBLibrary/SMB2/Commands/TreeDisconnectResponse.cs new file mode 100644 index 0000000..c4cb134 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/TreeDisconnectResponse.cs @@ -0,0 +1,49 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 TREE_DISCONNECT Response + /// + public class TreeDisconnectResponse : SMB2Command + { + public const int DeclaredSize = 4; + + public ushort StructureSize; + public ushort Reserved; + + public TreeDisconnectResponse() : base(SMB2CommandName.TreeDisconnect) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public TreeDisconnectResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + } + + public override int CommandLength + { + get + { + return DeclaredSize; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/WriteRequest.cs b/SMBLibrary/SMB2/Commands/WriteRequest.cs new file mode 100644 index 0000000..72b7c79 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/WriteRequest.cs @@ -0,0 +1,99 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 WRITE Request + /// + public class WriteRequest : SMB2Command + { + public const int FixedSize = 48; + public const int DeclaredSize = 49; + + public ushort StructureSize; + private ushort DataOffset; + private uint DataLength; + public ulong Offset; + public FileID FileId; + public uint Channel; + public uint RemainingBytes; + private ushort WriteChannelInfoOffset; + private ushort WriteChannelInfoLength; + public WriteFlags Flags; + public byte[] Data = new byte[0]; + public byte[] WriteChannelInfo = new byte[0]; + + public WriteRequest() : base(SMB2CommandName.Write) + { + StructureSize = DeclaredSize; + } + + public WriteRequest(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + DataOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + DataLength = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + Offset = LittleEndianConverter.ToUInt64(buffer, offset + SMB2Header.Length + 8); + FileId = new FileID(buffer, offset + SMB2Header.Length + 16); + Channel = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 32); + RemainingBytes = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 36); + WriteChannelInfoOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 40); + WriteChannelInfoLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 42); + Flags = (WriteFlags)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 44); + Data = ByteReader.ReadBytes(buffer, offset + DataOffset, (int)DataLength); + WriteChannelInfo = ByteReader.ReadBytes(buffer, offset + WriteChannelInfoOffset, WriteChannelInfoLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + // Note: DataLength is UInt32 while WriteChannelInfoOffset is UInt16 + // so it is best to put WriteChannelInfo before Data. + WriteChannelInfoOffset = 0; + WriteChannelInfoLength = (ushort)WriteChannelInfo.Length; + if (WriteChannelInfo.Length > 0) + { + WriteChannelInfoOffset = SMB2Header.Length + FixedSize; + } + DataOffset = 0; + DataLength = (uint)Data.Length; + if (Data.Length > 0) + { + DataOffset = (ushort)(WriteChannelInfoOffset + WriteChannelInfo.Length); + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, DataOffset); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, DataLength); + LittleEndianWriter.WriteUInt64(buffer, offset + 8, Offset); + FileId.WriteBytes(buffer, offset + 16); + LittleEndianWriter.WriteUInt32(buffer, offset + 32, Channel); + LittleEndianWriter.WriteUInt32(buffer, offset + 36, RemainingBytes); + LittleEndianWriter.WriteUInt16(buffer, offset + 40, WriteChannelInfoOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 42, WriteChannelInfoLength); + LittleEndianWriter.WriteUInt32(buffer, offset + 44, (uint)Flags); + if (WriteChannelInfo.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedSize, WriteChannelInfo); + } + if (Data.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedSize + WriteChannelInfo.Length, Data); + } + } + + public override int CommandLength + { + get + { + return FixedSize + Data.Length + WriteChannelInfo.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Commands/WriteResponse.cs b/SMBLibrary/SMB2/Commands/WriteResponse.cs new file mode 100644 index 0000000..572d5e1 --- /dev/null +++ b/SMBLibrary/SMB2/Commands/WriteResponse.cs @@ -0,0 +1,74 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// SMB2 WRITE Response + /// + public class WriteResponse : SMB2Command + { + public const int FixedSize = 16; + public const int DeclaredSize = 17; + + public ushort StructureSize; + public ushort Reserved; + public uint Count; + public uint Remaining; + private ushort WriteChannelInfoOffset; + private ushort WriteChannelInfoLength; + public byte[] WriteChannelInfo = new byte[0]; + + public WriteResponse() : base(SMB2CommandName.Write) + { + Header.IsResponse = true; + StructureSize = DeclaredSize; + } + + public WriteResponse(byte[] buffer, int offset) : base(buffer, offset) + { + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2); + Count = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 4); + Remaining = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 8); + WriteChannelInfoOffset = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 12); + WriteChannelInfoLength = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 14); + WriteChannelInfo = ByteReader.ReadBytes(buffer, offset + WriteChannelInfoOffset, WriteChannelInfoLength); + } + + public override void WriteCommandBytes(byte[] buffer, int offset) + { + WriteChannelInfoOffset = 0; + WriteChannelInfoLength = (ushort)WriteChannelInfo.Length; + if (WriteChannelInfo.Length > 0) + { + WriteChannelInfoOffset = SMB2Header.Length + FixedSize; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, Count); + LittleEndianWriter.WriteUInt32(buffer, offset + 8, Remaining); + LittleEndianWriter.WriteUInt16(buffer, offset + 12, WriteChannelInfoOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 14, WriteChannelInfoLength); + if (WriteChannelInfo.Length > 0) + { + ByteWriter.WriteBytes(buffer, offset + FixedSize, WriteChannelInfo); + } + } + + public override int CommandLength + { + get + { + return FixedSize + WriteChannelInfo.Length; + } + } + } +} diff --git a/SMBLibrary/SMB2/Enums/ChangeNotify/ChangeNotifyFlags.cs b/SMBLibrary/SMB2/Enums/ChangeNotify/ChangeNotifyFlags.cs new file mode 100644 index 0000000..9973906 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/ChangeNotify/ChangeNotifyFlags.cs @@ -0,0 +1,10 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum ChangeNotifyFlags : ushort + { + WatchTree = 0x0001, // SMB2_WATCH_TREE + } +} diff --git a/SMBLibrary/SMB2/Enums/ChangeNotify/NotifyChange.cs b/SMBLibrary/SMB2/Enums/ChangeNotify/NotifyChange.cs new file mode 100644 index 0000000..c854f2b --- /dev/null +++ b/SMBLibrary/SMB2/Enums/ChangeNotify/NotifyChange.cs @@ -0,0 +1,21 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum NotifyChange : uint + { + FileName = 0x0000001, // FILE_NOTIFY_CHANGE_FILE_NAME + DirName = 0x0000002, // FILE_NOTIFY_CHANGE_DIR_NAME + Attributes = 0x0000004, // FILE_NOTIFY_CHANGE_ATTRIBUTES + Size = 0x0000008, // FILE_NOTIFY_CHANGE_SIZE + LastWrite = 0x000000010, // FILE_NOTIFY_CHANGE_LAST_WRITE + LastAccess = 0x00000020, // FILE_NOTIFY_CHANGE_LAST_ACCESS + Creation = 0x00000040, // FILE_NOTIFY_CHANGE_CREATION + EA = 0x00000080, // FILE_NOTIFY_CHANGE_EA + Security = 0x00000100, // FILE_NOTIFY_CHANGE_SECURITY + StreamName = 0x00000200, // FILE_NOTIFY_CHANGE_STREAM_NAME + StreamSize = 0x00000400, // FILE_NOTIFY_CHANGE_STREAM_SIZE + StreamWrite = 0x00000800, // FILE_NOTIFY_CHANGE_STREAM_WRITE + } +} diff --git a/SMBLibrary/SMB2/Enums/Close/CloseFlags.cs b/SMBLibrary/SMB2/Enums/Close/CloseFlags.cs new file mode 100644 index 0000000..8a35fcd --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Close/CloseFlags.cs @@ -0,0 +1,10 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum CloseFlags : byte + { + PostQueryAttribute = 0x0001, // SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB + } +} diff --git a/SMBLibrary/SMB2/Enums/Create/CreateAction.cs b/SMBLibrary/SMB2/Enums/Create/CreateAction.cs new file mode 100644 index 0000000..70277a0 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Create/CreateAction.cs @@ -0,0 +1,11 @@ + +namespace SMBLibrary.SMB2 +{ + public enum CreateAction : uint + { + FILE_SUPERSEDED = 0x00000000, + FILE_OPENED = 0x00000001, + FILE_CREATED = 0x00000002, + FILE_OVERWRITTEN = 0x00000003, + } +} diff --git a/SMBLibrary/SMB2/Enums/Create/CreateResponseFlags.cs b/SMBLibrary/SMB2/Enums/Create/CreateResponseFlags.cs new file mode 100644 index 0000000..33b8ae4 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Create/CreateResponseFlags.cs @@ -0,0 +1,10 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum CreateResponseFlags : byte + { + ReparsePoint = 0x01, // SMB2_CREATE_FLAG_REPARSEPOINT + } +} diff --git a/SMBLibrary/SMB2/Enums/Create/ImpersonationLevel.cs b/SMBLibrary/SMB2/Enums/Create/ImpersonationLevel.cs new file mode 100644 index 0000000..553448c --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Create/ImpersonationLevel.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SMBLibrary.SMB2 +{ + public enum ImpersonationLevel : uint + { + Anonymous = 0x00000000, + Identification = 0x00000001, + Impersonation = 0x00000002, + Delegate = 0x00000003, + } +} diff --git a/SMBLibrary/SMB2/Enums/Create/OplockLevel.cs b/SMBLibrary/SMB2/Enums/Create/OplockLevel.cs new file mode 100644 index 0000000..2fbf6f2 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Create/OplockLevel.cs @@ -0,0 +1,14 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum OplockLevel : byte + { + None = 0x00, // SMB2_OPLOCK_LEVEL_NONE + Level2 = 0x01, // SMB2_OPLOCK_LEVEL_II + Exclusive = 0x08, // SMB2_OPLOCK_LEVEL_EXCLUSIVE + Batch = 0x09, // SMB2_OPLOCK_LEVEL_BATCH + Lease = 0xFF, // SMB2_OPLOCK_LEVEL_LEASE + } +} diff --git a/SMBLibrary/SMB2/Enums/IOCtl/IOCtlRequestFlags.cs b/SMBLibrary/SMB2/Enums/IOCtl/IOCtlRequestFlags.cs new file mode 100644 index 0000000..147e265 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/IOCtl/IOCtlRequestFlags.cs @@ -0,0 +1,10 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum IOCtlRequestFlags : uint + { + IsFSCtl = 0x00000001, // SMB2_0_IOCTL_IS_FSCTL + } +} diff --git a/SMBLibrary/SMB2/Enums/InfoType.cs b/SMBLibrary/SMB2/Enums/InfoType.cs new file mode 100644 index 0000000..309c25f --- /dev/null +++ b/SMBLibrary/SMB2/Enums/InfoType.cs @@ -0,0 +1,11 @@ + +namespace SMBLibrary.SMB2 +{ + public enum InfoType : byte + { + File = 0x01, // SMB2_0_INFO_FILE + FileSystem = 0x02, // SMB2_0_INFO_FILESYSTEM + Security = 0x03, // SMB2_0_INFO_SECURITY + Quota = 0x04, // SMB2_0_INFO_QUOTA + } +} diff --git a/SMBLibrary/SMB2/Enums/Negotiate/NegotiateContextType.cs b/SMBLibrary/SMB2/Enums/Negotiate/NegotiateContextType.cs new file mode 100644 index 0000000..f71cbde --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Negotiate/NegotiateContextType.cs @@ -0,0 +1,9 @@ + +namespace SMBLibrary.SMB2 +{ + public enum NegotiateContextType : ushort + { + SMB2_PREAUTH_INTEGRITY_CAPABILITIES = 0x0001, + SMB2_ENCRYPTION_CAPABILITIES = 0x0002, + } +} diff --git a/SMBLibrary/SMB2/Enums/Negotiate/SMB2Dialect.cs b/SMBLibrary/SMB2/Enums/Negotiate/SMB2Dialect.cs new file mode 100644 index 0000000..11e8bbc --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Negotiate/SMB2Dialect.cs @@ -0,0 +1,21 @@ + +namespace SMBLibrary.SMB2 +{ + public enum SMB2Dialect : ushort + { + SMB202 = 0x0202, // SMB 2.0.2 + SMB210 = 0x0210, // SMB 2.1 + SMB300 = 0x0300, // SMB 3.0 + SMB302 = 0x0302, // SMB 3.0.2 + SMB311 = 0x0311, // SMB 3.1.1 + + /// + /// indicates that the server implements SMB 2.1 or future dialect revisions and expects + /// the client to send a subsequent SMB2 Negotiate request to negotiate the actual SMB 2 + /// Protocol revision to be used. + /// The wildcard revision number is sent only in response to a multi-protocol negotiate + /// request with the "SMB 2.???" dialect string. + /// + SMB2xx = 0x02FF, // SMB 2.xx + } +} diff --git a/SMBLibrary/SMB2/Enums/Negotiate/SecurityMode.cs b/SMBLibrary/SMB2/Enums/Negotiate/SecurityMode.cs new file mode 100644 index 0000000..ee1d8c2 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Negotiate/SecurityMode.cs @@ -0,0 +1,9 @@ + +namespace SMBLibrary.SMB2 +{ + public enum SecurityMode : ushort + { + SigningEnabled = 0x0001, // SMB2_NEGOTIATE_SIGNING_ENABLED + SigningRequired = 0x0002, // SMB2_NEGOTIATE_SIGNING_REQUIRED + } +} diff --git a/SMBLibrary/SMB2/Enums/Negotiate/ServerCapabilities.cs b/SMBLibrary/SMB2/Enums/Negotiate/ServerCapabilities.cs new file mode 100644 index 0000000..9e57bc9 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Negotiate/ServerCapabilities.cs @@ -0,0 +1,16 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum ServerCapabilities : uint + { + DFS = 0x00000001, // SMB2_GLOBAL_CAP_DFS + Leasing = 0x00000002, // SMB2_GLOBAL_CAP_LEASING + LargeMTU = 0x0000004, // SMB2_GLOBAL_CAP_LARGE_MTU + MultiChannel = 0x0000008, // SMB2_GLOBAL_CAP_MULTI_CHANNEL + PersistentHandles = 0x00000010, // SMB2_GLOBAL_CAP_PERSISTENT_HANDLES + DirectoryLeasing = 0x00000020, // SMB2_GLOBAL_CAP_DIRECTORY_LEASING + Encryption = 0x00000040, // SMB2_GLOBAL_CAP_ENCRYPTION (SMB 3.x) + } +} diff --git a/SMBLibrary/SMB2/Enums/QueryDirectory/QueryDirectoryFlags.cs b/SMBLibrary/SMB2/Enums/QueryDirectory/QueryDirectoryFlags.cs new file mode 100644 index 0000000..ce66a12 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/QueryDirectory/QueryDirectoryFlags.cs @@ -0,0 +1,13 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum QueryDirectoryFlags : byte + { + SMB2_RESTART_SCANS = 0x01, + SMB2_RETURN_SINGLE_ENTRY = 0x02, + SMB2_INDEX_SPECIFIED = 0x04, + SMB2_REOPEN = 0x10, + } +} diff --git a/SMBLibrary/SMB2/Enums/Read/ReadFlags.cs b/SMBLibrary/SMB2/Enums/Read/ReadFlags.cs new file mode 100644 index 0000000..0f78398 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Read/ReadFlags.cs @@ -0,0 +1,10 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum ReadFlags : byte + { + Unbuffered = 0x01, // SMB2_READFLAG_READ_UNBUFFERED; + } +} diff --git a/SMBLibrary/SMB2/Enums/SMB2CommandName.cs b/SMBLibrary/SMB2/Enums/SMB2CommandName.cs new file mode 100644 index 0000000..5f2212f --- /dev/null +++ b/SMBLibrary/SMB2/Enums/SMB2CommandName.cs @@ -0,0 +1,26 @@ + +namespace SMBLibrary.SMB2 +{ + public enum SMB2CommandName : ushort + { + Negotiate = 0x0000, // SMB2 NEGOTIATE + SessionSetup = 0x0001, // SMB2 SESSION_SETUP + Logoff = 0x0002, // SMB2 LOGOFF + TreeConnect = 0x0003, // SMB2 TREE_CONNECT + TreeDisconnect = 0x0004, // SMB2 TREE_DISCONNECT + Create = 0x0005, // SMB2 CREATE + Close = 0x0006, // SMB2 CLOSE + Flush = 0x0007, // SMB2 FLUSH + Read = 0x0008, // SMB2 READ + Write = 0x0009, // SMB2 WRITE + Lock = 0x000A, // SMB2 LOCK + IOCtl = 0x000B, // SMB2 IOCTL + Cancel = 0x000C, // SMB2 CANCEL + Echo = 0x000D, // SMB2 ECHO + QueryDirectory = 0x000E, // SMB2 QUERY_DIRECTORY + ChangeNotify = 0x000F, // SMB2 CHANGE_NOTIFY + QueryInfo = 0x0010, // SMB2 QUERY_INFO + SetInfo = 0x0011, // SMB2 SET_INFO + OplockBreak = 0x0012, // SMB2 OPLOCK_BREAK + } +} diff --git a/SMBLibrary/SMB2/Enums/SMB2PacketHeaderFlags.cs b/SMBLibrary/SMB2/Enums/SMB2PacketHeaderFlags.cs new file mode 100644 index 0000000..5bb522f --- /dev/null +++ b/SMBLibrary/SMB2/Enums/SMB2PacketHeaderFlags.cs @@ -0,0 +1,14 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum SMB2PacketHeaderFlags : uint + { + ServerToRedir = 0x0000001, // SMB2_FLAGS_SERVER_TO_REDIR + AsyncCommand = 0x0000002, // SMB2_FLAGS_ASYNC_COMMAND + RelatedOperations = 0x0000004, // SMB2_FLAGS_RELATED_OPERATIONS + Signed = 0x0000008, // SMB2_FLAGS_SIGNED + DfsOperations = 0x10000000, // SMB2_FLAGS_DFS_OPERATIONS + } +} diff --git a/SMBLibrary/SMB2/Enums/SessionSetup/SessionFlags.cs b/SMBLibrary/SMB2/Enums/SessionSetup/SessionFlags.cs new file mode 100644 index 0000000..06f6a2a --- /dev/null +++ b/SMBLibrary/SMB2/Enums/SessionSetup/SessionFlags.cs @@ -0,0 +1,12 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum SessionFlags : ushort + { + IsGuest = 0x01, // SMB2_SESSION_FLAG_IS_GUEST + IsNull = 0x02, // SMB2_SESSION_FLAG_IS_NULL + EncryptData = 0x04, // SMB2_SESSION_FLAG_ENCRYPT_DATA (SMB 3.x) + } +} diff --git a/SMBLibrary/SMB2/Enums/SessionSetup/SessionSetupFlags.cs b/SMBLibrary/SMB2/Enums/SessionSetup/SessionSetupFlags.cs new file mode 100644 index 0000000..d57373f --- /dev/null +++ b/SMBLibrary/SMB2/Enums/SessionSetup/SessionSetupFlags.cs @@ -0,0 +1,10 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum SessionSetupFlags : byte + { + Binding = 0x01, // SMB2_SESSION_FLAG_BINDING + } +} diff --git a/SMBLibrary/SMB2/Enums/TreeConnect/ShareCapabilities.cs b/SMBLibrary/SMB2/Enums/TreeConnect/ShareCapabilities.cs new file mode 100644 index 0000000..ebee8b4 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/TreeConnect/ShareCapabilities.cs @@ -0,0 +1,14 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum ShareCapabilities : uint + { + Dfs = 0x00000008, // SMB2_SHARE_CAP_DFS + ContinuousAvailability = 0x00000010, // SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY + Scaleout = 0x00000020, // SMB2_SHARE_CAP_SCALEOUT + Cluster = 0x00000040, // SMB2_SHARE_CAP_CLUSTER + Asymmetric = 0x00000080, // SMB2_SHARE_CAP_ASYMMETRIC + } +} diff --git a/SMBLibrary/SMB2/Enums/TreeConnect/ShareFlags.cs b/SMBLibrary/SMB2/Enums/TreeConnect/ShareFlags.cs new file mode 100644 index 0000000..e68d23a --- /dev/null +++ b/SMBLibrary/SMB2/Enums/TreeConnect/ShareFlags.cs @@ -0,0 +1,23 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum ShareFlags : uint + { + ManualCaching = 0x00000000, // SMB2_SHAREFLAG_MANUAL_CACHING + AutoCaching = 0x00000010, // SMB2_SHAREFLAG_AUTO_CACHING + VdoCaching = 0x00000020, // SMB2_SHAREFLAG_VDO_CACHING + NoCaching = 0x00000030, // SMB2_SHAREFLAG_NO_CACHING + Dfs = 0x00000001, // SMB2_SHAREFLAG_DFS + DfsRoot = 0x00000002, // SMB2_SHAREFLAG_DFS_ROOT + RestrictExclusiveOpens = 0x00000100, // SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS + ForceSharedDelete = 0x00000200, // SMB2_SHAREFLAG_FORCE_SHARED_DELETE + AllowNamespaceCaching = 0x00000400, // SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING + AccessBasedDirectoryEnum = 0x00000800, // SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM + ForceLevel2Oplock = 0x00001000, // SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK + EnableHashV1 = 0x00002000, // SMB2_SHAREFLAG_ENABLE_HASH_V1 (SMB 2.1) + EnableHashV2 = 0x00004000, // SMB2_SHAREFLAG_ENABLE_HASH_V2 (SMB 3.x) + EncryptData = 0x00008000, // SMB2_SHAREFLAG_ENCRYPT_DATA (SMB 3.x) + } +} diff --git a/SMBLibrary/SMB2/Enums/TreeConnect/ShareType.cs b/SMBLibrary/SMB2/Enums/TreeConnect/ShareType.cs new file mode 100644 index 0000000..4adccf8 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/TreeConnect/ShareType.cs @@ -0,0 +1,10 @@ + +namespace SMBLibrary.SMB2 +{ + public enum ShareType : byte + { + Disk = 0x01, // SMB2_SHARE_TYPE_DISK + Pipe = 0x02, // SMB2_SHARE_TYPE_PIPE + Print = 0x03, // SMB2_SHARE_TYPE_PRINT + } +} diff --git a/SMBLibrary/SMB2/Enums/Write/WriteFlags.cs b/SMBLibrary/SMB2/Enums/Write/WriteFlags.cs new file mode 100644 index 0000000..c511503 --- /dev/null +++ b/SMBLibrary/SMB2/Enums/Write/WriteFlags.cs @@ -0,0 +1,10 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + public enum WriteFlags : uint + { + WriteThrough = 0x00000001, // SMB2_WRITEFLAG_WRITE_THROUGH + Unbuffered = 0x00000002, // SMB2_WRITEFLAG_WRITE_UNBUFFERED + } +} diff --git a/SMBLibrary/SMB2/SMB2Header.cs b/SMBLibrary/SMB2/SMB2Header.cs new file mode 100644 index 0000000..a748e68 --- /dev/null +++ b/SMBLibrary/SMB2/SMB2Header.cs @@ -0,0 +1,141 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + public class SMB2Header + { + public const int Length = 64; + public static readonly byte[] ProtocolSignature = new byte[] { 0xFE, 0x53, 0x4D, 0x42 }; + + public byte[] ProtocolId; // 4 bytes, 0xFE followed by "SMB" + public ushort StructureSize; + public ushort CreditCharge; + public NTStatus Status; + public SMB2CommandName Command; + public ushort Credits; // CreditRequest or CreditResponse (The number of credits granted to the client) + public SMB2PacketHeaderFlags Flags; + public uint NextCommand; // offset in bytes + public ulong MessageID; + public uint Reserved; // Sync + public uint TreeID; // Sync + public ulong AsyncID; // Async + public ulong SessionID; + public byte[] Signature; // 16 bytes (present if SMB2_FLAGS_SIGNED is set) + + public SMB2Header(SMB2CommandName commandName) + { + ProtocolId = ProtocolSignature; + StructureSize = Length; + Command = commandName; + } + + public SMB2Header(byte[] buffer, int offset) + { + ProtocolId = ByteReader.ReadBytes(buffer, offset + 0, 4); + StructureSize = LittleEndianConverter.ToUInt16(buffer, offset + 4); + CreditCharge = LittleEndianConverter.ToUInt16(buffer, offset + 6); + Status = (NTStatus)LittleEndianConverter.ToUInt32(buffer, offset + 8); + Command = (SMB2CommandName)LittleEndianConverter.ToUInt16(buffer, offset + 12); + Credits = LittleEndianConverter.ToUInt16(buffer, offset + 14); + Flags = (SMB2PacketHeaderFlags)LittleEndianConverter.ToUInt32(buffer, offset + 16); + NextCommand = LittleEndianConverter.ToUInt32(buffer, offset + 20); + MessageID = LittleEndianConverter.ToUInt64(buffer, offset + 24); + if ((Flags & SMB2PacketHeaderFlags.AsyncCommand) > 0) + { + AsyncID = LittleEndianConverter.ToUInt64(buffer, offset + 32); + } + else + { + Reserved = LittleEndianConverter.ToUInt32(buffer, offset + 32); + TreeID = LittleEndianConverter.ToUInt32(buffer, offset + 36); + } + SessionID = LittleEndianConverter.ToUInt64(buffer, offset + 40); + if ((Flags & SMB2PacketHeaderFlags.Signed) > 0) + { + Signature = ByteReader.ReadBytes(buffer, offset + 48, 16); + } + } + + public void WriteBytes(byte[] buffer, int offset) + { + ByteWriter.WriteBytes(buffer, offset + 0, ProtocolId); + LittleEndianWriter.WriteUInt16(buffer, offset + 4, StructureSize); + LittleEndianWriter.WriteUInt16(buffer, offset + 6, CreditCharge); + LittleEndianWriter.WriteUInt32(buffer, offset + 8, (uint)Status); + LittleEndianWriter.WriteUInt16(buffer, offset + 12, (ushort)Command); + LittleEndianWriter.WriteUInt16(buffer, offset + 14, Credits); + LittleEndianWriter.WriteUInt32(buffer, offset + 16, (uint)Flags); + LittleEndianWriter.WriteUInt32(buffer, offset + 20, NextCommand); + LittleEndianWriter.WriteUInt64(buffer, offset + 24, MessageID); + if ((Flags & SMB2PacketHeaderFlags.AsyncCommand) > 0) + { + LittleEndianWriter.WriteUInt64(buffer, offset + 32, AsyncID); + } + else + { + LittleEndianWriter.WriteUInt32(buffer, offset + 32, Reserved); + LittleEndianWriter.WriteUInt32(buffer, offset + 36, TreeID); + } + LittleEndianWriter.WriteUInt64(buffer, offset + 40, SessionID); + if ((Flags & SMB2PacketHeaderFlags.Signed) > 0) + { + ByteWriter.WriteBytes(buffer, offset + 48, Signature); + } + } + + public bool IsResponse + { + get + { + return (Flags & SMB2PacketHeaderFlags.ServerToRedir) > 0; + } + set + { + if (value) + { + Flags |= SMB2PacketHeaderFlags.ServerToRedir; + } + else + { + Flags &= ~SMB2PacketHeaderFlags.ServerToRedir; + } + } + } + + public bool IsRelatedOperations + { + get + { + return (Flags & SMB2PacketHeaderFlags.RelatedOperations) > 0; + } + set + { + if (value) + { + Flags |= SMB2PacketHeaderFlags.RelatedOperations; + } + else + { + Flags &= ~SMB2PacketHeaderFlags.RelatedOperations; + } + } + } + + public static bool IsValidSMB2Header(byte[] buffer) + { + if (buffer.Length >= 4) + { + byte[] signature = ByteReader.ReadBytes(buffer, 0, 4); + return ByteUtils.AreByteArraysEqual(signature, ProtocolSignature); + } + return false; + } + } +} diff --git a/SMBLibrary/SMB2/Structures/CreateContext.cs b/SMBLibrary/SMB2/Structures/CreateContext.cs new file mode 100644 index 0000000..5a9669b --- /dev/null +++ b/SMBLibrary/SMB2/Structures/CreateContext.cs @@ -0,0 +1,150 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// [MS-SMB2] 2.2.13.2 - SMB2_CREATE_CONTEXT + /// + public class CreateContext + { + public int FixedLength = 16; + + /// + /// The offset from the beginning of this Create Context to the beginning of a subsequent 8-byte aligned Create Context. + /// This field MUST be set to 0 if there are no subsequent contexts. + /// + public uint Next; + private ushort NameOffset; // The offset from the beginning of this structure to the 8-byte aligned name value + private ushort NameLength; + public ushort Reserved; + private ushort DataOffset; // The offset from the beginning of this structure to the 8-byte aligned data payload + private uint DataLength; + public string Name = String.Empty; + public byte[] Data = new byte[0]; + + public CreateContext() + { + } + + public CreateContext(byte[] buffer, int offset) + { + Next = LittleEndianConverter.ToUInt32(buffer, offset + 0); + NameOffset = LittleEndianConverter.ToUInt16(buffer, offset + 4); + NameLength = LittleEndianConverter.ToUInt16(buffer, offset + 6); + Reserved = LittleEndianConverter.ToUInt16(buffer, offset + 8); + DataOffset = LittleEndianConverter.ToUInt16(buffer, offset + 10); + DataLength = LittleEndianConverter.ToUInt32(buffer, offset + 12); + if (NameLength > 0) + { + Name = ByteReader.ReadUTF16String(buffer, offset + NameOffset, NameLength / 2); + } + if (DataLength > 0) + { + Data = ByteReader.ReadBytes(buffer, offset + DataOffset, (int)DataLength); + } + } + + private void WriteBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt32(buffer, offset + 0, Next); + NameOffset = 0; + NameLength = (ushort)(Name.Length * 2); + if (Name.Length > 0) + { + NameOffset = (ushort)FixedLength; + } + LittleEndianWriter.WriteUInt16(buffer, offset + 4, NameOffset); + LittleEndianWriter.WriteUInt16(buffer, offset + 6, NameLength); + LittleEndianWriter.WriteUInt16(buffer, offset + 8, Reserved); + DataOffset = 0; + DataLength = (uint)Data.Length; + if (Data.Length > 0) + { + int paddedNameLength = (int)Math.Ceiling((double)(Name.Length * 2) / 8) * 8; + DataOffset = (ushort)(FixedLength + paddedNameLength); + } + LittleEndianWriter.WriteUInt16(buffer, offset + 10, DataOffset); + ByteWriter.WriteUTF16String(buffer, NameOffset, Name); + ByteWriter.WriteBytes(buffer, DataOffset, Data); + } + + public int Length + { + get + { + if (Data.Length > 0) + { + int paddedNameLength = (int)Math.Ceiling((double)(Name.Length * 2) / 8) * 8; + return FixedLength + paddedNameLength + Data.Length; + } + else + { + return FixedLength + Name.Length * 2; + } + } + } + + public static List ReadCreateContextList(byte[] buffer, int offset) + { + List result = new List(); + CreateContext createContext; + do + { + createContext = new CreateContext(buffer, offset); + result.Add(createContext); + offset += (int)createContext.Next; + } + while (createContext.Next != 0); + + return result; + } + + public static void WriteCreateContextList(byte[] buffer, int offset, List createContexts) + { + for (int index = 0; index < createContexts.Count; index++) + { + CreateContext createContext = createContexts[index]; + int length = createContext.Length; + int paddedLength = (int)Math.Ceiling((double)length / 8) * 8; + if (index < createContexts.Count - 1) + { + createContext.Next = (uint)paddedLength; + } + else + { + createContext.Next = 0; + } + createContext.WriteBytes(buffer, offset); + offset += paddedLength; + } + } + + public static int GetCreateContextListLength(List createContexts) + { + int result = 0; + for(int index = 0; index < createContexts.Count; index++) + { + CreateContext createContext = createContexts[index]; + int length = createContext.Length; + if (index < createContexts.Count - 1) + { + int paddedLength = (int)Math.Ceiling((double)length / 8) * 8; + result += paddedLength; + } + else + { + result += length; + } + } + return result; + } + } +} diff --git a/SMBLibrary/SMB2/Structures/Enums/LockFlags.cs b/SMBLibrary/SMB2/Structures/Enums/LockFlags.cs new file mode 100644 index 0000000..31c7a8b --- /dev/null +++ b/SMBLibrary/SMB2/Structures/Enums/LockFlags.cs @@ -0,0 +1,13 @@ +using System; + +namespace SMBLibrary.SMB2 +{ + [Flags] + public enum LockFlags : uint + { + SharedLock = 0x00000001, // SMB2_LOCKFLAG_SHARED_LOCK + ExclusiveLock = 0x00000002, // SMB2_LOCKFLAG_EXCLUSIVE_LOCK + Unlock = 0x00000004, // SMB2_LOCKFLAG_UNLOCK + FailImmediately = 0x00000008, // SMB2_LOCKFLAG_FAIL_IMMEDIATELY + } +} diff --git a/SMBLibrary/SMB2/Structures/FileID.cs b/SMBLibrary/SMB2/Structures/FileID.cs new file mode 100644 index 0000000..33eeb19 --- /dev/null +++ b/SMBLibrary/SMB2/Structures/FileID.cs @@ -0,0 +1,34 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// [MS-SMB2] 2.2.14.1 - SMB2_FILEID + /// + public struct FileID + { + public const int Length = 16; + + public ulong Persistent; + public ulong Volatile; + + public FileID(byte[] buffer, int offset) + { + Persistent = LittleEndianConverter.ToUInt64(buffer, offset + 0); + Volatile = LittleEndianConverter.ToUInt64(buffer, offset + 8); + } + + public void WriteBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt64(buffer, offset + 0, Persistent); + LittleEndianWriter.WriteUInt64(buffer, offset + 8, Volatile); + } + } +} diff --git a/SMBLibrary/SMB2/Structures/LockElement.cs b/SMBLibrary/SMB2/Structures/LockElement.cs new file mode 100644 index 0000000..5bc9790 --- /dev/null +++ b/SMBLibrary/SMB2/Structures/LockElement.cs @@ -0,0 +1,58 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + public struct LockElement + { + public const int StructureLength = 24; + + public ulong Offset; + public ulong Length; + public LockFlags Flags; + public uint Reserved; + + public LockElement(byte[] buffer, int offset) + { + Offset = LittleEndianConverter.ToUInt64(buffer, offset + 0); + Length = LittleEndianConverter.ToUInt64(buffer, offset + 8); + Flags = (LockFlags)LittleEndianConverter.ToUInt32(buffer, offset + 16); + Reserved = LittleEndianConverter.ToUInt32(buffer, offset + 20); + } + + public void WriteBytes(byte[] buffer, int offset) + { + LittleEndianWriter.WriteUInt64(buffer, offset + 0, Offset); + LittleEndianWriter.WriteUInt64(buffer, offset + 8, Length); + LittleEndianWriter.WriteUInt64(buffer, offset + 16, (uint)Flags); + LittleEndianWriter.WriteUInt64(buffer, offset + 20, Reserved); + } + + public static List ReadLockList(byte[] buffer, int offset, int lockCount) + { + List result = new List(); + for(int lockIndex = 0; lockIndex > lockCount; lockIndex++) + { + LockElement element = new LockElement(buffer, offset + lockIndex * StructureLength); + result.Add(element); + } + return result; + } + + public static void WriteLockList(byte[] buffer, int offset, List locks) + { + for (int lockIndex = 0; lockIndex > locks.Count; lockIndex++) + { + LockElement element = locks[lockIndex]; + element.WriteBytes(buffer, offset + lockIndex * StructureLength); + } + } + } +} diff --git a/SMBLibrary/SMB2/Structures/NegotiateContext.cs b/SMBLibrary/SMB2/Structures/NegotiateContext.cs new file mode 100644 index 0000000..c36f64d --- /dev/null +++ b/SMBLibrary/SMB2/Structures/NegotiateContext.cs @@ -0,0 +1,99 @@ +/* Copyright (C) 2017 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, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using Utilities; + +namespace SMBLibrary.SMB2 +{ + /// + /// [MS-SMB2] 2.2.3.1 - NEGOTIATE_CONTEXT + /// + public class NegotiateContext + { + public const int FixedLength = 8; + + public NegotiateContextType ContextType; + private ushort DataLength; + public uint Reserved; + public byte[] Data = new byte[0]; + + public NegotiateContext() + { + } + + public NegotiateContext(byte[] buffer, int offset) + { + ContextType = (NegotiateContextType)LittleEndianConverter.ToUInt16(buffer, offset + 0); + DataLength = LittleEndianConverter.ToUInt16(buffer, offset + 2); + Reserved = LittleEndianConverter.ToUInt32(buffer, offset + 4); + ByteReader.ReadBytes(buffer, offset + 8, DataLength); + } + + public void WriteBytes(byte[] buffer, int offset) + { + DataLength = (ushort)Data.Length; + LittleEndianWriter.WriteUInt16(buffer, offset + 0, (ushort)ContextType); + LittleEndianWriter.WriteUInt16(buffer, offset + 2, DataLength); + LittleEndianWriter.WriteUInt32(buffer, offset + 4, Reserved); + ByteWriter.WriteBytes(buffer, offset + 8, Data); + } + + public int Length + { + get + { + return FixedLength + Data.Length; + } + } + + public static List ReadNegotiateContextList(byte[] buffer, int offset, int count) + { + List result = new List(); + for (int index = 0; index < count; index++) + { + NegotiateContext context = new NegotiateContext(buffer, offset); + result.Add(context); + offset += context.Length; + } + return result; + } + + public static void WriteNegotiateContextList(byte[] buffer, int offset, List negotiateContextList) + { + // Subsequent negotiate contexts MUST appear at the first 8-byte aligned offset following the previous negotiate context + for (int index = 0; index < negotiateContextList.Count; index++) + { + NegotiateContext context = negotiateContextList[index]; + int length = context.Length; + int paddedLength = (int)Math.Ceiling((double)length / 8) * 8; + context.WriteBytes(buffer, offset); + offset += paddedLength; + } + } + + public static int GetNegotiateContextListLength(List negotiateContextList) + { + int result = 0; + for (int index = 0; index < negotiateContextList.Count; index++) + { + NegotiateContext context = negotiateContextList[index]; + int length = context.Length; + if (index < negotiateContextList.Count - 1) + { + int paddedLength = (int)Math.Ceiling((double)length / 8) * 8; + result += paddedLength; + } + else + { + result += length; + } + } + return result; + } + } +} diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj index 80fe48f..abf35a0 100644 --- a/SMBLibrary/SMBLibrary.csproj +++ b/SMBLibrary/SMBLibrary.csproj @@ -398,6 +398,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +