diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2017-08-16 02:43:41 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2017-08-16 02:43:41 -0400 |
| commit | bfcd1b520fd79b893e721ba916ae5e1656407d2f (patch) | |
| tree | 6a05119800484435fb384da25c6390054a27c3c3 /Emby.Server.Implementations/IO/SharpCifs/Ntlmssp | |
| parent | e3531534b85aeaaa3e4aaf462d5e77ea142dc762 (diff) | |
merge common implementations and server implementations
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/Ntlmssp')
5 files changed, 1701 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs new file mode 100644 index 0000000000..116f71b754 --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmFlags.cs @@ -0,0 +1,197 @@ +// This code is derived from jcifs smb client library <jcifs at samba dot org> +// Ported by J. Arturo <webmaster at komodosoft dot net> +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +namespace SharpCifs.Ntlmssp +{ + /// <summary>Flags used during negotiation of NTLMSSP authentication.</summary> + /// <remarks>Flags used during negotiation of NTLMSSP authentication.</remarks> + public abstract class NtlmFlags + { + /// <summary>Indicates whether Unicode strings are supported or used.</summary> + /// <remarks>Indicates whether Unicode strings are supported or used.</remarks> + public const int NtlmsspNegotiateUnicode = unchecked(0x00000001); + + /// <summary>Indicates whether OEM strings are supported or used.</summary> + /// <remarks>Indicates whether OEM strings are supported or used.</remarks> + public const int NtlmsspNegotiateOem = unchecked(0x00000002); + + /// <summary> + /// Indicates whether the authentication target is requested from + /// the server. + /// </summary> + /// <remarks> + /// Indicates whether the authentication target is requested from + /// the server. + /// </remarks> + public const int NtlmsspRequestTarget = unchecked(0x00000004); + + /// <summary> + /// Specifies that communication across the authenticated channel + /// should carry a digital signature (message integrity). + /// </summary> + /// <remarks> + /// Specifies that communication across the authenticated channel + /// should carry a digital signature (message integrity). + /// </remarks> + public const int NtlmsspNegotiateSign = unchecked(0x00000010); + + /// <summary> + /// Specifies that communication across the authenticated channel + /// should be encrypted (message confidentiality). + /// </summary> + /// <remarks> + /// Specifies that communication across the authenticated channel + /// should be encrypted (message confidentiality). + /// </remarks> + public const int NtlmsspNegotiateSeal = unchecked(0x00000020); + + /// <summary>Indicates datagram authentication.</summary> + /// <remarks>Indicates datagram authentication.</remarks> + public const int NtlmsspNegotiateDatagramStyle = unchecked(0x00000040); + + /// <summary> + /// Indicates that the LAN Manager session key should be used for + /// signing and sealing authenticated communication. + /// </summary> + /// <remarks> + /// Indicates that the LAN Manager session key should be used for + /// signing and sealing authenticated communication. + /// </remarks> + public const int NtlmsspNegotiateLmKey = unchecked(0x00000080); + + public const int NtlmsspNegotiateNetware = unchecked(0x00000100); + + /// <summary>Indicates support for NTLM authentication.</summary> + /// <remarks>Indicates support for NTLM authentication.</remarks> + public const int NtlmsspNegotiateNtlm = unchecked(0x00000200); + + /// <summary> + /// Indicates whether the OEM-formatted domain name in which the + /// client workstation has membership is supplied in the Type-1 message. + /// </summary> + /// <remarks> + /// Indicates whether the OEM-formatted domain name in which the + /// client workstation has membership is supplied in the Type-1 message. + /// This is used in the negotation of local authentication. + /// </remarks> + public const int NtlmsspNegotiateOemDomainSupplied = unchecked(0x00001000); + + /// <summary> + /// Indicates whether the OEM-formatted workstation name is supplied + /// in the Type-1 message. + /// </summary> + /// <remarks> + /// Indicates whether the OEM-formatted workstation name is supplied + /// in the Type-1 message. This is used in the negotiation of local + /// authentication. + /// </remarks> + public const int NtlmsspNegotiateOemWorkstationSupplied = unchecked(0x00002000); + + /// <summary> + /// Sent by the server to indicate that the server and client are + /// on the same machine. + /// </summary> + /// <remarks> + /// Sent by the server to indicate that the server and client are + /// on the same machine. This implies that the server will include + /// a local security context handle in the Type 2 message, for + /// use in local authentication. + /// </remarks> + public const int NtlmsspNegotiateLocalCall = unchecked(0x00004000); + + /// <summary> + /// Indicates that authenticated communication between the client + /// and server should carry a "dummy" digital signature. + /// </summary> + /// <remarks> + /// Indicates that authenticated communication between the client + /// and server should carry a "dummy" digital signature. + /// </remarks> + public const int NtlmsspNegotiateAlwaysSign = unchecked(0x00008000); + + /// <summary> + /// Sent by the server in the Type 2 message to indicate that the + /// target authentication realm is a domain. + /// </summary> + /// <remarks> + /// Sent by the server in the Type 2 message to indicate that the + /// target authentication realm is a domain. + /// </remarks> + public const int NtlmsspTargetTypeDomain = unchecked(0x00010000); + + /// <summary> + /// Sent by the server in the Type 2 message to indicate that the + /// target authentication realm is a server. + /// </summary> + /// <remarks> + /// Sent by the server in the Type 2 message to indicate that the + /// target authentication realm is a server. + /// </remarks> + public const int NtlmsspTargetTypeServer = unchecked(0x00020000); + + /// <summary> + /// Sent by the server in the Type 2 message to indicate that the + /// target authentication realm is a share (presumably for share-level + /// authentication). + /// </summary> + /// <remarks> + /// Sent by the server in the Type 2 message to indicate that the + /// target authentication realm is a share (presumably for share-level + /// authentication). + /// </remarks> + public const int NtlmsspTargetTypeShare = unchecked(0x00040000); + + /// <summary> + /// Indicates that the NTLM2 signing and sealing scheme should be used + /// for protecting authenticated communications. + /// </summary> + /// <remarks> + /// Indicates that the NTLM2 signing and sealing scheme should be used + /// for protecting authenticated communications. This refers to a + /// particular session security scheme, and is not related to the use + /// of NTLMv2 authentication. + /// </remarks> + public const int NtlmsspNegotiateNtlm2 = unchecked(0x00080000); + + public const int NtlmsspRequestInitResponse = unchecked(0x00100000); + + public const int NtlmsspRequestAcceptResponse = unchecked(0x00200000); + + public const int NtlmsspRequestNonNtSessionKey = unchecked(0x00400000 + ); + + /// <summary> + /// Sent by the server in the Type 2 message to indicate that it is + /// including a Target Information block in the message. + /// </summary> + /// <remarks> + /// Sent by the server in the Type 2 message to indicate that it is + /// including a Target Information block in the message. The Target + /// Information block is used in the calculation of the NTLMv2 response. + /// </remarks> + public const int NtlmsspNegotiateTargetInfo = unchecked(0x00800000); + + /// <summary>Indicates that 128-bit encryption is supported.</summary> + /// <remarks>Indicates that 128-bit encryption is supported.</remarks> + public const int NtlmsspNegotiate128 = unchecked(0x20000000); + + public const int NtlmsspNegotiateKeyExch = unchecked(0x40000000); + + /// <summary>Indicates that 56-bit encryption is supported.</summary> + /// <remarks>Indicates that 56-bit encryption is supported.</remarks> + public const int NtlmsspNegotiate56 = unchecked((int)(0x80000000)); + } +} diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs new file mode 100644 index 0000000000..02827d2d07 --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/NtlmMessage.cs @@ -0,0 +1,140 @@ +// This code is derived from jcifs smb client library <jcifs at samba dot org> +// Ported by J. Arturo <webmaster at komodosoft dot net> +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; + +namespace SharpCifs.Ntlmssp +{ + /// <summary>Abstract superclass for all NTLMSSP messages.</summary> + /// <remarks>Abstract superclass for all NTLMSSP messages.</remarks> + public abstract class NtlmMessage : NtlmFlags + { + /// <summary>The NTLMSSP "preamble".</summary> + /// <remarks>The NTLMSSP "preamble".</remarks> + protected internal static readonly byte[] NtlmsspSignature = { unchecked( + (byte)('N')), unchecked((byte)('T')), unchecked((byte)('L')), + unchecked((byte)('M')), unchecked((byte)('S')), unchecked((byte + )('S')), unchecked((byte)('P')), unchecked(0) }; + + private static readonly string OemEncoding = Config.DefaultOemEncoding; + + protected internal static readonly string UniEncoding = "UTF-16LE"; + + private int _flags; + + /// <summary>Returns the flags currently in use for this message.</summary> + /// <remarks>Returns the flags currently in use for this message.</remarks> + /// <returns> + /// An <code>int</code> containing the flags in use for this + /// message. + /// </returns> + public virtual int GetFlags() + { + return _flags; + } + + /// <summary>Sets the flags for this message.</summary> + /// <remarks>Sets the flags for this message.</remarks> + /// <param name="flags">The flags for this message.</param> + public virtual void SetFlags(int flags) + { + this._flags = flags; + } + + /// <summary>Returns the status of the specified flag.</summary> + /// <remarks>Returns the status of the specified flag.</remarks> + /// <param name="flag">The flag to test (i.e., <code>NTLMSSP_NEGOTIATE_OEM</code>).</param> + /// <returns>A <code>boolean</code> indicating whether the flag is set.</returns> + public virtual bool GetFlag(int flag) + { + return (GetFlags() & flag) != 0; + } + + /// <summary>Sets or clears the specified flag.</summary> + /// <remarks>Sets or clears the specified flag.</remarks> + /// <param name="flag"> + /// The flag to set/clear (i.e., + /// <code>NTLMSSP_NEGOTIATE_OEM</code>). + /// </param> + /// <param name="value"> + /// Indicates whether to set (<code>true</code>) or + /// clear (<code>false</code>) the specified flag. + /// </param> + public virtual void SetFlag(int flag, bool value) + { + SetFlags(value ? (GetFlags() | flag) : (GetFlags() & (unchecked((int)(0xffffffff) + ) ^ flag))); + } + + internal static int ReadULong(byte[] src, int index) + { + return (src[index] & unchecked(0xff)) | ((src[index + 1] & unchecked(0xff)) << 8) | ((src[index + 2] & unchecked(0xff)) << 16) | ((src[index + + 3] & unchecked(0xff)) << 24); + } + + internal static int ReadUShort(byte[] src, int index) + { + return (src[index] & unchecked(0xff)) | ((src[index + 1] & unchecked(0xff)) << 8); + } + + internal static byte[] ReadSecurityBuffer(byte[] src, int index) + { + int length = ReadUShort(src, index); + int offset = ReadULong(src, index + 4); + byte[] buffer = new byte[length]; + Array.Copy(src, offset, buffer, 0, length); + return buffer; + } + + internal static void WriteULong(byte[] dest, int offset, int value) + { + dest[offset] = unchecked((byte)(value & unchecked(0xff))); + dest[offset + 1] = unchecked((byte)(value >> 8 & unchecked(0xff))); + dest[offset + 2] = unchecked((byte)(value >> 16 & unchecked(0xff))); + dest[offset + 3] = unchecked((byte)(value >> 24 & unchecked(0xff))); + } + + internal static void WriteUShort(byte[] dest, int offset, int value) + { + dest[offset] = unchecked((byte)(value & unchecked(0xff))); + dest[offset + 1] = unchecked((byte)(value >> 8 & unchecked(0xff))); + } + + internal static void WriteSecurityBuffer(byte[] dest, int offset, int bodyOffset, + byte[] src) + { + int length = (src != null) ? src.Length : 0; + if (length == 0) + { + return; + } + WriteUShort(dest, offset, length); + WriteUShort(dest, offset + 2, length); + WriteULong(dest, offset + 4, bodyOffset); + Array.Copy(src, 0, dest, bodyOffset, length); + } + + internal static string GetOemEncoding() + { + return OemEncoding; + } + + /// <summary>Returns the raw byte representation of this message.</summary> + /// <remarks>Returns the raw byte representation of this message.</remarks> + /// <returns>A <code>byte[]</code> containing the raw message material.</returns> + public abstract byte[] ToByteArray(); + } +} diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs new file mode 100644 index 0000000000..afcf5ec7e7 --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type1Message.cs @@ -0,0 +1,249 @@ +// This code is derived from jcifs smb client library <jcifs at samba dot org> +// Ported by J. Arturo <webmaster at komodosoft dot net> +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.IO; +using SharpCifs.Netbios; +using SharpCifs.Util; +using SharpCifs.Util.Sharpen; + +namespace SharpCifs.Ntlmssp +{ + /// <summary>Represents an NTLMSSP Type-1 message.</summary> + /// <remarks>Represents an NTLMSSP Type-1 message.</remarks> + public class Type1Message : NtlmMessage + { + private static readonly int DefaultFlags; + + private static readonly string DefaultDomain; + + private static readonly string DefaultWorkstation; + + private string _suppliedDomain; + + private string _suppliedWorkstation; + + static Type1Message() + { + DefaultFlags = NtlmsspNegotiateNtlm | (Config.GetBoolean("jcifs.smb.client.useUnicode" + , true) ? NtlmsspNegotiateUnicode : NtlmsspNegotiateOem); + DefaultDomain = Config.GetProperty("jcifs.smb.client.domain", null); + string defaultWorkstation = null; + try + { + defaultWorkstation = NbtAddress.GetLocalHost().GetHostName(); + } + catch (UnknownHostException) + { + } + DefaultWorkstation = defaultWorkstation; + } + + /// <summary> + /// Creates a Type-1 message using default values from the current + /// environment. + /// </summary> + /// <remarks> + /// Creates a Type-1 message using default values from the current + /// environment. + /// </remarks> + public Type1Message() : this(GetDefaultFlags(), GetDefaultDomain(), GetDefaultWorkstation + ()) + { + } + + /// <summary>Creates a Type-1 message with the specified parameters.</summary> + /// <remarks>Creates a Type-1 message with the specified parameters.</remarks> + /// <param name="flags">The flags to apply to this message.</param> + /// <param name="suppliedDomain">The supplied authentication domain.</param> + /// <param name="suppliedWorkstation">The supplied workstation name.</param> + public Type1Message(int flags, string suppliedDomain, string suppliedWorkstation) + { + SetFlags(GetDefaultFlags() | flags); + SetSuppliedDomain(suppliedDomain); + if (suppliedWorkstation == null) + { + suppliedWorkstation = GetDefaultWorkstation(); + } + SetSuppliedWorkstation(suppliedWorkstation); + } + + /// <summary>Creates a Type-1 message using the given raw Type-1 material.</summary> + /// <remarks>Creates a Type-1 message using the given raw Type-1 material.</remarks> + /// <param name="material">The raw Type-1 material used to construct this message.</param> + /// <exception cref="System.IO.IOException">If an error occurs while parsing the material. + /// </exception> + public Type1Message(byte[] material) + { + Parse(material); + } + + /// <summary>Returns the supplied authentication domain.</summary> + /// <remarks>Returns the supplied authentication domain.</remarks> + /// <returns>A <code>String</code> containing the supplied domain.</returns> + public virtual string GetSuppliedDomain() + { + return _suppliedDomain; + } + + /// <summary>Sets the supplied authentication domain for this message.</summary> + /// <remarks>Sets the supplied authentication domain for this message.</remarks> + /// <param name="suppliedDomain">The supplied domain for this message.</param> + public virtual void SetSuppliedDomain(string suppliedDomain) + { + this._suppliedDomain = suppliedDomain; + } + + /// <summary>Returns the supplied workstation name.</summary> + /// <remarks>Returns the supplied workstation name.</remarks> + /// <returns>A <code>String</code> containing the supplied workstation name.</returns> + public virtual string GetSuppliedWorkstation() + { + return _suppliedWorkstation; + } + + /// <summary>Sets the supplied workstation name for this message.</summary> + /// <remarks>Sets the supplied workstation name for this message.</remarks> + /// <param name="suppliedWorkstation">The supplied workstation for this message.</param> + public virtual void SetSuppliedWorkstation(string suppliedWorkstation) + { + this._suppliedWorkstation = suppliedWorkstation; + } + + public override byte[] ToByteArray() + { + try + { + string suppliedDomain = GetSuppliedDomain(); + string suppliedWorkstation = GetSuppliedWorkstation(); + int flags = GetFlags(); + bool hostInfo = false; + byte[] domain = new byte[0]; + if (!string.IsNullOrEmpty(suppliedDomain)) + { + hostInfo = true; + flags |= NtlmsspNegotiateOemDomainSupplied; + domain = Runtime.GetBytesForString(suppliedDomain.ToUpper(), GetOemEncoding + ()); + } + else + { + flags &= (NtlmsspNegotiateOemDomainSupplied ^ unchecked((int)(0xffffffff))); + } + byte[] workstation = new byte[0]; + if (!string.IsNullOrEmpty(suppliedWorkstation)) + { + hostInfo = true; + flags |= NtlmsspNegotiateOemWorkstationSupplied; + workstation = Runtime.GetBytesForString(suppliedWorkstation.ToUpper(), GetOemEncoding + ()); + } + else + { + flags &= (NtlmsspNegotiateOemWorkstationSupplied ^ unchecked((int)(0xffffffff + ))); + } + byte[] type1 = new byte[hostInfo ? (32 + domain.Length + workstation.Length) : 16 + ]; + Array.Copy(NtlmsspSignature, 0, type1, 0, 8); + WriteULong(type1, 8, 1); + WriteULong(type1, 12, flags); + if (hostInfo) + { + WriteSecurityBuffer(type1, 16, 32, domain); + WriteSecurityBuffer(type1, 24, 32 + domain.Length, workstation); + } + return type1; + } + catch (IOException ex) + { + throw new InvalidOperationException(ex.Message); + } + } + + public override string ToString() + { + string suppliedDomain = GetSuppliedDomain(); + string suppliedWorkstation = GetSuppliedWorkstation(); + return "Type1Message[suppliedDomain=" + (suppliedDomain ?? "null" + ) + ",suppliedWorkstation=" + (suppliedWorkstation ?? "null" + ) + ",flags=0x" + Hexdump.ToHexString(GetFlags(), 8) + "]"; + } + + /// <summary> + /// Returns the default flags for a generic Type-1 message in the + /// current environment. + /// </summary> + /// <remarks> + /// Returns the default flags for a generic Type-1 message in the + /// current environment. + /// </remarks> + /// <returns>An <code>int</code> containing the default flags.</returns> + public static int GetDefaultFlags() + { + return DefaultFlags; + } + + /// <summary>Returns the default domain from the current environment.</summary> + /// <remarks>Returns the default domain from the current environment.</remarks> + /// <returns>A <code>String</code> containing the default domain.</returns> + public static string GetDefaultDomain() + { + return DefaultDomain; + } + + /// <summary>Returns the default workstation from the current environment.</summary> + /// <remarks>Returns the default workstation from the current environment.</remarks> + /// <returns>A <code>String</code> containing the default workstation.</returns> + public static string GetDefaultWorkstation() + { + return DefaultWorkstation; + } + + /// <exception cref="System.IO.IOException"></exception> + private void Parse(byte[] material) + { + for (int i = 0; i < 8; i++) + { + if (material[i] != NtlmsspSignature[i]) + { + throw new IOException("Not an NTLMSSP message."); + } + } + if (ReadULong(material, 8) != 1) + { + throw new IOException("Not a Type 1 message."); + } + int flags = ReadULong(material, 12); + string suppliedDomain = null; + if ((flags & NtlmsspNegotiateOemDomainSupplied) != 0) + { + byte[] domain = ReadSecurityBuffer(material, 16); + suppliedDomain = Runtime.GetStringForBytes(domain, GetOemEncoding()); + } + string suppliedWorkstation = null; + if ((flags & NtlmsspNegotiateOemWorkstationSupplied) != 0) + { + byte[] workstation = ReadSecurityBuffer(material, 24); + suppliedWorkstation = Runtime.GetStringForBytes(workstation, GetOemEncoding + ()); + } + SetFlags(flags); + SetSuppliedDomain(suppliedDomain); + SetSuppliedWorkstation(suppliedWorkstation); + } + } +} diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs new file mode 100644 index 0000000000..104e5b0fdf --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type2Message.cs @@ -0,0 +1,438 @@ +// This code is derived from jcifs smb client library <jcifs at samba dot org> +// Ported by J. Arturo <webmaster at komodosoft dot net> +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.IO; +using SharpCifs.Netbios; +using SharpCifs.Util; +using SharpCifs.Util.Sharpen; + +namespace SharpCifs.Ntlmssp +{ + /// <summary>Represents an NTLMSSP Type-2 message.</summary> + /// <remarks>Represents an NTLMSSP Type-2 message.</remarks> + public class Type2Message : NtlmMessage + { + private static readonly int DefaultFlags; + + private static readonly string DefaultDomain; + + private static readonly byte[] DefaultTargetInformation; + + private byte[] _challenge; + + private string _target; + + private byte[] _context; + + private byte[] _targetInformation; + + static Type2Message() + { + DefaultFlags = NtlmsspNegotiateNtlm | (Config.GetBoolean("jcifs.smb.client.useUnicode" + , true) ? NtlmsspNegotiateUnicode : NtlmsspNegotiateOem); + DefaultDomain = Config.GetProperty("jcifs.smb.client.domain", null); + byte[] domain = new byte[0]; + if (DefaultDomain != null) + { + try + { + domain = Runtime.GetBytesForString(DefaultDomain, UniEncoding); + } + catch (IOException) + { + } + } + int domainLength = domain.Length; + byte[] server = new byte[0]; + try + { + string host = NbtAddress.GetLocalHost().GetHostName(); + if (host != null) + { + try + { + server = Runtime.GetBytesForString(host, UniEncoding); + } + catch (IOException) + { + } + } + } + catch (UnknownHostException) + { + } + int serverLength = server.Length; + byte[] targetInfo = new byte[(domainLength > 0 ? domainLength + 4 : 0) + (serverLength + > 0 ? serverLength + 4 : 0) + 4]; + int offset = 0; + if (domainLength > 0) + { + WriteUShort(targetInfo, offset, 2); + offset += 2; + WriteUShort(targetInfo, offset, domainLength); + offset += 2; + Array.Copy(domain, 0, targetInfo, offset, domainLength); + offset += domainLength; + } + if (serverLength > 0) + { + WriteUShort(targetInfo, offset, 1); + offset += 2; + WriteUShort(targetInfo, offset, serverLength); + offset += 2; + Array.Copy(server, 0, targetInfo, offset, serverLength); + } + DefaultTargetInformation = targetInfo; + } + + /// <summary> + /// Creates a Type-2 message using default values from the current + /// environment. + /// </summary> + /// <remarks> + /// Creates a Type-2 message using default values from the current + /// environment. + /// </remarks> + public Type2Message() : this(GetDefaultFlags(), null, null) + { + } + + /// <summary> + /// Creates a Type-2 message in response to the given Type-1 message + /// using default values from the current environment. + /// </summary> + /// <remarks> + /// Creates a Type-2 message in response to the given Type-1 message + /// using default values from the current environment. + /// </remarks> + /// <param name="type1">The Type-1 message which this represents a response to.</param> + public Type2Message(Type1Message type1) : this(type1, null, null) + { + } + + /// <summary>Creates a Type-2 message in response to the given Type-1 message.</summary> + /// <remarks>Creates a Type-2 message in response to the given Type-1 message.</remarks> + /// <param name="type1">The Type-1 message which this represents a response to.</param> + /// <param name="challenge">The challenge from the domain controller/server.</param> + /// <param name="target">The authentication target.</param> + public Type2Message(Type1Message type1, byte[] challenge, string target) : this(GetDefaultFlags + (type1), challenge, (type1 != null && target == null && type1.GetFlag(NtlmsspRequestTarget + )) ? GetDefaultDomain() : target) + { + } + + /// <summary>Creates a Type-2 message with the specified parameters.</summary> + /// <remarks>Creates a Type-2 message with the specified parameters.</remarks> + /// <param name="flags">The flags to apply to this message.</param> + /// <param name="challenge">The challenge from the domain controller/server.</param> + /// <param name="target">The authentication target.</param> + public Type2Message(int flags, byte[] challenge, string target) + { + SetFlags(flags); + SetChallenge(challenge); + SetTarget(target); + if (target != null) + { + SetTargetInformation(GetDefaultTargetInformation()); + } + } + + /// <summary>Creates a Type-2 message using the given raw Type-2 material.</summary> + /// <remarks>Creates a Type-2 message using the given raw Type-2 material.</remarks> + /// <param name="material">The raw Type-2 material used to construct this message.</param> + /// <exception cref="System.IO.IOException">If an error occurs while parsing the material. + /// </exception> + public Type2Message(byte[] material) + { + Parse(material); + } + + /// <summary>Returns the challenge for this message.</summary> + /// <remarks>Returns the challenge for this message.</remarks> + /// <returns>A <code>byte[]</code> containing the challenge.</returns> + public virtual byte[] GetChallenge() + { + return _challenge; + } + + /// <summary>Sets the challenge for this message.</summary> + /// <remarks>Sets the challenge for this message.</remarks> + /// <param name="challenge">The challenge from the domain controller/server.</param> + public virtual void SetChallenge(byte[] challenge) + { + this._challenge = challenge; + } + + /// <summary>Returns the authentication target.</summary> + /// <remarks>Returns the authentication target.</remarks> + /// <returns>A <code>String</code> containing the authentication target.</returns> + public virtual string GetTarget() + { + return _target; + } + + /// <summary>Sets the authentication target.</summary> + /// <remarks>Sets the authentication target.</remarks> + /// <param name="target">The authentication target.</param> + public virtual void SetTarget(string target) + { + this._target = target; + } + + /// <summary>Returns the target information block.</summary> + /// <remarks>Returns the target information block.</remarks> + /// <returns> + /// A <code>byte[]</code> containing the target information block. + /// The target information block is used by the client to create an + /// NTLMv2 response. + /// </returns> + public virtual byte[] GetTargetInformation() + { + return _targetInformation; + } + + /// <summary>Sets the target information block.</summary> + /// <remarks> + /// Sets the target information block. + /// The target information block is used by the client to create + /// an NTLMv2 response. + /// </remarks> + /// <param name="targetInformation">The target information block.</param> + public virtual void SetTargetInformation(byte[] targetInformation) + { + this._targetInformation = targetInformation; + } + + /// <summary>Returns the local security context.</summary> + /// <remarks>Returns the local security context.</remarks> + /// <returns> + /// A <code>byte[]</code> containing the local security + /// context. This is used by the client to negotiate local + /// authentication. + /// </returns> + public virtual byte[] GetContext() + { + return _context; + } + + /// <summary>Sets the local security context.</summary> + /// <remarks> + /// Sets the local security context. This is used by the client + /// to negotiate local authentication. + /// </remarks> + /// <param name="context">The local security context.</param> + public virtual void SetContext(byte[] context) + { + this._context = context; + } + + public override byte[] ToByteArray() + { + try + { + string targetName = GetTarget(); + byte[] challenge = GetChallenge(); + byte[] context = GetContext(); + byte[] targetInformation = GetTargetInformation(); + int flags = GetFlags(); + byte[] target = new byte[0]; + if ((flags & NtlmsspRequestTarget) != 0) + { + if (!string.IsNullOrEmpty(targetName)) + { + target = (flags & NtlmsspNegotiateUnicode) != 0 ? Runtime.GetBytesForString + (targetName, UniEncoding) : Runtime.GetBytesForString(targetName.ToUpper + (), GetOemEncoding()); + } + else + { + flags &= (unchecked((int)(0xffffffff)) ^ NtlmsspRequestTarget); + } + } + if (targetInformation != null) + { + flags |= NtlmsspNegotiateTargetInfo; + // empty context is needed for padding when t.i. is supplied. + if (context == null) + { + context = new byte[8]; + } + } + int data = 32; + if (context != null) + { + data += 8; + } + if (targetInformation != null) + { + data += 8; + } + byte[] type2 = new byte[data + target.Length + (targetInformation != null ? targetInformation + .Length : 0)]; + Array.Copy(NtlmsspSignature, 0, type2, 0, 8); + WriteULong(type2, 8, 2); + WriteSecurityBuffer(type2, 12, data, target); + WriteULong(type2, 20, flags); + Array.Copy(challenge ?? new byte[8], 0, type2, 24, 8); + if (context != null) + { + Array.Copy(context, 0, type2, 32, 8); + } + if (targetInformation != null) + { + WriteSecurityBuffer(type2, 40, data + target.Length, targetInformation); + } + return type2; + } + catch (IOException ex) + { + throw new InvalidOperationException(ex.Message); + } + } + + public override string ToString() + { + string target = GetTarget(); + byte[] challenge = GetChallenge(); + byte[] context = GetContext(); + byte[] targetInformation = GetTargetInformation(); + return "Type2Message[target=" + target + ",challenge=" + (challenge == null ? "null" + : "<" + challenge.Length + " bytes>") + ",context=" + (context == null ? "null" + : "<" + context.Length + " bytes>") + ",targetInformation=" + (targetInformation + == null ? "null" : "<" + targetInformation.Length + " bytes>") + ",flags=0x" + + Hexdump.ToHexString(GetFlags(), 8) + "]"; + } + + /// <summary> + /// Returns the default flags for a generic Type-2 message in the + /// current environment. + /// </summary> + /// <remarks> + /// Returns the default flags for a generic Type-2 message in the + /// current environment. + /// </remarks> + /// <returns>An <code>int</code> containing the default flags.</returns> + public static int GetDefaultFlags() + { + return DefaultFlags; + } + + /// <summary> + /// Returns the default flags for a Type-2 message created in response + /// to the given Type-1 message in the current environment. + /// </summary> + /// <remarks> + /// Returns the default flags for a Type-2 message created in response + /// to the given Type-1 message in the current environment. + /// </remarks> + /// <returns>An <code>int</code> containing the default flags.</returns> + public static int GetDefaultFlags(Type1Message type1) + { + if (type1 == null) + { + return DefaultFlags; + } + int flags = NtlmsspNegotiateNtlm; + int type1Flags = type1.GetFlags(); + flags |= ((type1Flags & NtlmsspNegotiateUnicode) != 0) ? NtlmsspNegotiateUnicode + : NtlmsspNegotiateOem; + if ((type1Flags & NtlmsspRequestTarget) != 0) + { + string domain = GetDefaultDomain(); + if (domain != null) + { + flags |= NtlmsspRequestTarget | NtlmsspTargetTypeDomain; + } + } + return flags; + } + + /// <summary>Returns the default domain from the current environment.</summary> + /// <remarks>Returns the default domain from the current environment.</remarks> + /// <returns>A <code>String</code> containing the domain.</returns> + public static string GetDefaultDomain() + { + return DefaultDomain; + } + + public static byte[] GetDefaultTargetInformation() + { + return DefaultTargetInformation; + } + + /// <exception cref="System.IO.IOException"></exception> + private void Parse(byte[] material) + { + for (int i = 0; i < 8; i++) + { + if (material[i] != NtlmsspSignature[i]) + { + throw new IOException("Not an NTLMSSP message."); + } + } + if (ReadULong(material, 8) != 2) + { + throw new IOException("Not a Type 2 message."); + } + int flags = ReadULong(material, 20); + SetFlags(flags); + string target = null; + byte[] bytes = ReadSecurityBuffer(material, 12); + if (bytes.Length != 0) + { + target = Runtime.GetStringForBytes(bytes, ((flags & NtlmsspNegotiateUnicode + ) != 0) ? UniEncoding : GetOemEncoding()); + } + SetTarget(target); + for (int i1 = 24; i1 < 32; i1++) + { + if (material[i1] != 0) + { + byte[] challenge = new byte[8]; + Array.Copy(material, 24, challenge, 0, 8); + SetChallenge(challenge); + break; + } + } + int offset = ReadULong(material, 16); + // offset of targetname start + if (offset == 32 || material.Length == 32) + { + return; + } + for (int i2 = 32; i2 < 40; i2++) + { + if (material[i2] != 0) + { + byte[] context = new byte[8]; + Array.Copy(material, 32, context, 0, 8); + SetContext(context); + break; + } + } + if (offset == 40 || material.Length == 40) + { + return; + } + bytes = ReadSecurityBuffer(material, 40); + if (bytes.Length != 0) + { + SetTargetInformation(bytes); + } + } + } +} diff --git a/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs new file mode 100644 index 0000000000..9a2a37f3cf --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/Ntlmssp/Type3Message.cs @@ -0,0 +1,677 @@ +// This code is derived from jcifs smb client library <jcifs at samba dot org> +// Ported by J. Arturo <webmaster at komodosoft dot net> +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.IO; +using SharpCifs.Netbios; +using SharpCifs.Smb; +using SharpCifs.Util; +using SharpCifs.Util.Sharpen; + +namespace SharpCifs.Ntlmssp +{ + /// <summary>Represents an NTLMSSP Type-3 message.</summary> + /// <remarks>Represents an NTLMSSP Type-3 message.</remarks> + public class Type3Message : NtlmMessage + { + internal const long MillisecondsBetween1970And1601 = 11644473600000L; + + private static readonly int DefaultFlags; + + private static readonly string DefaultDomain; + + private static readonly string DefaultUser; + + private static readonly string DefaultPassword; + + private static readonly string DefaultWorkstation; + + private static readonly int LmCompatibility; + + //private static readonly SecureRandom RANDOM = new SecureRandom(); + + private byte[] _lmResponse; + + private byte[] _ntResponse; + + private string _domain; + + private string _user; + + private string _workstation; + + private byte[] _masterKey; + + private byte[] _sessionKey; + + static Type3Message() + { + DefaultFlags = NtlmsspNegotiateNtlm | (Config.GetBoolean("jcifs.smb.client.useUnicode" + , true) ? NtlmsspNegotiateUnicode : NtlmsspNegotiateOem); + DefaultDomain = Config.GetProperty("jcifs.smb.client.domain", null); + DefaultUser = Config.GetProperty("jcifs.smb.client.username", null); + DefaultPassword = Config.GetProperty("jcifs.smb.client.password", null); + string defaultWorkstation = null; + try + { + defaultWorkstation = NbtAddress.GetLocalHost().GetHostName(); + } + catch (UnknownHostException) + { + } + DefaultWorkstation = defaultWorkstation; + LmCompatibility = Config.GetInt("jcifs.smb.lmCompatibility", 3); + } + + /// <summary> + /// Creates a Type-3 message using default values from the current + /// environment. + /// </summary> + /// <remarks> + /// Creates a Type-3 message using default values from the current + /// environment. + /// </remarks> + public Type3Message() + { + SetFlags(GetDefaultFlags()); + SetDomain(GetDefaultDomain()); + SetUser(GetDefaultUser()); + SetWorkstation(GetDefaultWorkstation()); + } + + /// <summary> + /// Creates a Type-3 message in response to the given Type-2 message + /// using default values from the current environment. + /// </summary> + /// <remarks> + /// Creates a Type-3 message in response to the given Type-2 message + /// using default values from the current environment. + /// </remarks> + /// <param name="type2">The Type-2 message which this represents a response to.</param> + public Type3Message(Type2Message type2) + { + SetFlags(GetDefaultFlags(type2)); + SetWorkstation(GetDefaultWorkstation()); + string domain = GetDefaultDomain(); + SetDomain(domain); + string user = GetDefaultUser(); + SetUser(user); + string password = GetDefaultPassword(); + switch (LmCompatibility) + { + case 0: + case 1: + { + SetLmResponse(GetLMResponse(type2, password)); + SetNtResponse(GetNTResponse(type2, password)); + break; + } + + case 2: + { + byte[] nt = GetNTResponse(type2, password); + SetLmResponse(nt); + SetNtResponse(nt); + break; + } + + case 3: + case 4: + case 5: + { + byte[] clientChallenge = new byte[8]; + //RANDOM.NextBytes(clientChallenge); + SetLmResponse(GetLMv2Response(type2, domain, user, password, clientChallenge)); + break; + } + + default: + { + SetLmResponse(GetLMResponse(type2, password)); + SetNtResponse(GetNTResponse(type2, password)); + break; + } + } + } + + /// <summary>Creates a Type-3 message in response to the given Type-2 message.</summary> + /// <remarks>Creates a Type-3 message in response to the given Type-2 message.</remarks> + /// <param name="type2">The Type-2 message which this represents a response to.</param> + /// <param name="password">The password to use when constructing the response.</param> + /// <param name="domain">The domain in which the user has an account.</param> + /// <param name="user">The username for the authenticating user.</param> + /// <param name="workstation"> + /// The workstation from which authentication is + /// taking place. + /// </param> + public Type3Message(Type2Message type2, string password, string domain, string user + , string workstation, int flags) + { + SetFlags(flags | GetDefaultFlags(type2)); + if (workstation == null) + { + workstation = GetDefaultWorkstation(); + } + SetWorkstation(workstation); + SetDomain(domain); + SetUser(user); + switch (LmCompatibility) + { + case 0: + case 1: + { + if ((GetFlags() & NtlmsspNegotiateNtlm2) == 0) + { + SetLmResponse(GetLMResponse(type2, password)); + SetNtResponse(GetNTResponse(type2, password)); + } + else + { + // NTLM2 Session Response + byte[] clientChallenge = new byte[24]; + //RANDOM.NextBytes(clientChallenge); + Arrays.Fill(clientChallenge, 8, 24, unchecked((byte)unchecked(0x00))); + // NTLMv1 w/ NTLM2 session sec and key exch all been verified with a debug build of smbclient + byte[] responseKeyNt = NtlmPasswordAuthentication.NtowFv1(password); + byte[] ntlm2Response = NtlmPasswordAuthentication.GetNtlm2Response(responseKeyNt, + type2.GetChallenge(), clientChallenge); + SetLmResponse(clientChallenge); + SetNtResponse(ntlm2Response); + if ((GetFlags() & NtlmsspNegotiateSign) == NtlmsspNegotiateSign) + { + byte[] sessionNonce = new byte[16]; + Array.Copy(type2.GetChallenge(), 0, sessionNonce, 0, 8); + Array.Copy(clientChallenge, 0, sessionNonce, 8, 8); + Md4 md4 = new Md4(); + md4.Update(responseKeyNt); + byte[] userSessionKey = md4.Digest(); + Hmact64 hmac = new Hmact64(userSessionKey); + hmac.Update(sessionNonce); + byte[] ntlm2SessionKey = hmac.Digest(); + if ((GetFlags() & NtlmsspNegotiateKeyExch) != 0) + { + _masterKey = new byte[16]; + //RANDOM.NextBytes(masterKey); + byte[] exchangedKey = new byte[16]; + Rc4 rc4 = new Rc4(ntlm2SessionKey); + rc4.Update(_masterKey, 0, 16, exchangedKey, 0); + SetSessionKey(exchangedKey); + } + else + { + _masterKey = ntlm2SessionKey; + SetSessionKey(_masterKey); + } + } + } + break; + } + + case 2: + { + byte[] nt = GetNTResponse(type2, password); + SetLmResponse(nt); + SetNtResponse(nt); + break; + } + + case 3: + case 4: + case 5: + { + byte[] responseKeyNt1 = NtlmPasswordAuthentication.NtowFv2(domain, user, password + ); + byte[] clientChallenge1 = new byte[8]; + //RANDOM.NextBytes(clientChallenge_1); + SetLmResponse(GetLMv2Response(type2, domain, user, password, clientChallenge1)); + byte[] clientChallenge2 = new byte[8]; + //RANDOM.NextBytes(clientChallenge2); + SetNtResponse(GetNtlMv2Response(type2, responseKeyNt1, clientChallenge2)); + if ((GetFlags() & NtlmsspNegotiateSign) == NtlmsspNegotiateSign) + { + Hmact64 hmac = new Hmact64(responseKeyNt1); + hmac.Update(_ntResponse, 0, 16); + // only first 16 bytes of ntResponse + byte[] userSessionKey = hmac.Digest(); + if ((GetFlags() & NtlmsspNegotiateKeyExch) != 0) + { + _masterKey = new byte[16]; + //RANDOM.NextBytes(masterKey); + byte[] exchangedKey = new byte[16]; + Rc4 rc4 = new Rc4(userSessionKey); + rc4.Update(_masterKey, 0, 16, exchangedKey, 0); + SetSessionKey(exchangedKey); + } + else + { + _masterKey = userSessionKey; + SetSessionKey(_masterKey); + } + } + break; + } + + default: + { + SetLmResponse(GetLMResponse(type2, password)); + SetNtResponse(GetNTResponse(type2, password)); + break; + } + } + } + + /// <summary>Creates a Type-3 message with the specified parameters.</summary> + /// <remarks>Creates a Type-3 message with the specified parameters.</remarks> + /// <param name="flags">The flags to apply to this message.</param> + /// <param name="lmResponse">The LanManager/LMv2 response.</param> + /// <param name="ntResponse">The NT/NTLMv2 response.</param> + /// <param name="domain">The domain in which the user has an account.</param> + /// <param name="user">The username for the authenticating user.</param> + /// <param name="workstation"> + /// The workstation from which authentication is + /// taking place. + /// </param> + public Type3Message(int flags, byte[] lmResponse, byte[] ntResponse, string domain + , string user, string workstation) + { + SetFlags(flags); + SetLmResponse(lmResponse); + SetNtResponse(ntResponse); + SetDomain(domain); + SetUser(user); + SetWorkstation(workstation); + } + + /// <summary>Creates a Type-3 message using the given raw Type-3 material.</summary> + /// <remarks>Creates a Type-3 message using the given raw Type-3 material.</remarks> + /// <param name="material">The raw Type-3 material used to construct this message.</param> + /// <exception cref="System.IO.IOException">If an error occurs while parsing the material. + /// </exception> + public Type3Message(byte[] material) + { + Parse(material); + } + + /// <summary>Returns the LanManager/LMv2 response.</summary> + /// <remarks>Returns the LanManager/LMv2 response.</remarks> + /// <returns>A <code>byte[]</code> containing the LanManager response.</returns> + public virtual byte[] GetLMResponse() + { + return _lmResponse; + } + + /// <summary>Sets the LanManager/LMv2 response for this message.</summary> + /// <remarks>Sets the LanManager/LMv2 response for this message.</remarks> + /// <param name="lmResponse">The LanManager response.</param> + public virtual void SetLmResponse(byte[] lmResponse) + { + this._lmResponse = lmResponse; + } + + /// <summary>Returns the NT/NTLMv2 response.</summary> + /// <remarks>Returns the NT/NTLMv2 response.</remarks> + /// <returns>A <code>byte[]</code> containing the NT/NTLMv2 response.</returns> + public virtual byte[] GetNTResponse() + { + return _ntResponse; + } + + /// <summary>Sets the NT/NTLMv2 response for this message.</summary> + /// <remarks>Sets the NT/NTLMv2 response for this message.</remarks> + /// <param name="ntResponse">The NT/NTLMv2 response.</param> + public virtual void SetNtResponse(byte[] ntResponse) + { + this._ntResponse = ntResponse; + } + + /// <summary>Returns the domain in which the user has an account.</summary> + /// <remarks>Returns the domain in which the user has an account.</remarks> + /// <returns>A <code>String</code> containing the domain for the user.</returns> + public virtual string GetDomain() + { + return _domain; + } + + /// <summary>Sets the domain for this message.</summary> + /// <remarks>Sets the domain for this message.</remarks> + /// <param name="domain">The domain.</param> + public virtual void SetDomain(string domain) + { + this._domain = domain; + } + + /// <summary>Returns the username for the authenticating user.</summary> + /// <remarks>Returns the username for the authenticating user.</remarks> + /// <returns>A <code>String</code> containing the user for this message.</returns> + public virtual string GetUser() + { + return _user; + } + + /// <summary>Sets the user for this message.</summary> + /// <remarks>Sets the user for this message.</remarks> + /// <param name="user">The user.</param> + public virtual void SetUser(string user) + { + this._user = user; + } + + /// <summary>Returns the workstation from which authentication is being performed.</summary> + /// <remarks>Returns the workstation from which authentication is being performed.</remarks> + /// <returns>A <code>String</code> containing the workstation.</returns> + public virtual string GetWorkstation() + { + return _workstation; + } + + /// <summary>Sets the workstation for this message.</summary> + /// <remarks>Sets the workstation for this message.</remarks> + /// <param name="workstation">The workstation.</param> + public virtual void SetWorkstation(string workstation) + { + this._workstation = workstation; + } + + /// <summary> + /// The real session key if the regular session key is actually + /// the encrypted version used for key exchange. + /// </summary> + /// <remarks> + /// The real session key if the regular session key is actually + /// the encrypted version used for key exchange. + /// </remarks> + /// <returns>A <code>byte[]</code> containing the session key.</returns> + public virtual byte[] GetMasterKey() + { + return _masterKey; + } + + /// <summary>Returns the session key.</summary> + /// <remarks>Returns the session key.</remarks> + /// <returns>A <code>byte[]</code> containing the session key.</returns> + public virtual byte[] GetSessionKey() + { + return _sessionKey; + } + + /// <summary>Sets the session key.</summary> + /// <remarks>Sets the session key.</remarks> + /// <param name="sessionKey">The session key.</param> + public virtual void SetSessionKey(byte[] sessionKey) + { + this._sessionKey = sessionKey; + } + + public override byte[] ToByteArray() + { + try + { + int flags = GetFlags(); + bool unicode = (flags & NtlmsspNegotiateUnicode) != 0; + string oem = unicode ? null : GetOemEncoding(); + string domainName = GetDomain(); + byte[] domain = null; + if (!string.IsNullOrEmpty(domainName)) + { + domain = unicode ? Runtime.GetBytesForString(domainName, UniEncoding) : + Runtime.GetBytesForString(domainName, oem); + } + int domainLength = (domain != null) ? domain.Length : 0; + string userName = GetUser(); + byte[] user = null; + if (!string.IsNullOrEmpty(userName)) + { + user = unicode ? Runtime.GetBytesForString(userName, UniEncoding) : Runtime.GetBytesForString + (userName.ToUpper(), oem); + } + int userLength = (user != null) ? user.Length : 0; + string workstationName = GetWorkstation(); + byte[] workstation = null; + if (!string.IsNullOrEmpty(workstationName)) + { + workstation = unicode ? Runtime.GetBytesForString(workstationName, UniEncoding + ) : Runtime.GetBytesForString(workstationName.ToUpper(), oem); + } + int workstationLength = (workstation != null) ? workstation.Length : 0; + byte[] lmResponse = GetLMResponse(); + int lmLength = (lmResponse != null) ? lmResponse.Length : 0; + byte[] ntResponse = GetNTResponse(); + int ntLength = (ntResponse != null) ? ntResponse.Length : 0; + byte[] sessionKey = GetSessionKey(); + int keyLength = (sessionKey != null) ? sessionKey.Length : 0; + byte[] type3 = new byte[64 + domainLength + userLength + workstationLength + lmLength + + ntLength + keyLength]; + Array.Copy(NtlmsspSignature, 0, type3, 0, 8); + WriteULong(type3, 8, 3); + int offset = 64; + WriteSecurityBuffer(type3, 12, offset, lmResponse); + offset += lmLength; + WriteSecurityBuffer(type3, 20, offset, ntResponse); + offset += ntLength; + WriteSecurityBuffer(type3, 28, offset, domain); + offset += domainLength; + WriteSecurityBuffer(type3, 36, offset, user); + offset += userLength; + WriteSecurityBuffer(type3, 44, offset, workstation); + offset += workstationLength; + WriteSecurityBuffer(type3, 52, offset, sessionKey); + WriteULong(type3, 60, flags); + return type3; + } + catch (IOException ex) + { + throw new InvalidOperationException(ex.Message); + } + } + + public override string ToString() + { + string user = GetUser(); + string domain = GetDomain(); + string workstation = GetWorkstation(); + byte[] lmResponse = GetLMResponse(); + byte[] ntResponse = GetNTResponse(); + byte[] sessionKey = GetSessionKey(); + return "Type3Message[domain=" + domain + ",user=" + user + ",workstation=" + workstation + + ",lmResponse=" + (lmResponse == null ? "null" : "<" + lmResponse.Length + " bytes>" + ) + ",ntResponse=" + (ntResponse == null ? "null" : "<" + ntResponse.Length + " bytes>" + ) + ",sessionKey=" + (sessionKey == null ? "null" : "<" + sessionKey.Length + " bytes>" + ) + ",flags=0x" + Hexdump.ToHexString(GetFlags(), 8) + "]"; + } + + /// <summary> + /// Returns the default flags for a generic Type-3 message in the + /// current environment. + /// </summary> + /// <remarks> + /// Returns the default flags for a generic Type-3 message in the + /// current environment. + /// </remarks> + /// <returns>An <code>int</code> containing the default flags.</returns> + public static int GetDefaultFlags() + { + return DefaultFlags; + } + + /// <summary> + /// Returns the default flags for a Type-3 message created in response + /// to the given Type-2 message in the current environment. + /// </summary> + /// <remarks> + /// Returns the default flags for a Type-3 message created in response + /// to the given Type-2 message in the current environment. + /// </remarks> + /// <returns>An <code>int</code> containing the default flags.</returns> + public static int GetDefaultFlags(Type2Message type2) + { + if (type2 == null) + { + return DefaultFlags; + } + int flags = NtlmsspNegotiateNtlm; + flags |= ((type2.GetFlags() & NtlmsspNegotiateUnicode) != 0) ? NtlmsspNegotiateUnicode + : NtlmsspNegotiateOem; + return flags; + } + + /// <summary> + /// Constructs the LanManager response to the given Type-2 message using + /// the supplied password. + /// </summary> + /// <remarks> + /// Constructs the LanManager response to the given Type-2 message using + /// the supplied password. + /// </remarks> + /// <param name="type2">The Type-2 message.</param> + /// <param name="password">The password.</param> + /// <returns>A <code>byte[]</code> containing the LanManager response.</returns> + public static byte[] GetLMResponse(Type2Message type2, string password) + { + if (type2 == null || password == null) + { + return null; + } + return NtlmPasswordAuthentication.GetPreNtlmResponse(password, type2.GetChallenge + ()); + } + + public static byte[] GetLMv2Response(Type2Message type2, string domain, string user + , string password, byte[] clientChallenge) + { + if (type2 == null || domain == null || user == null || password == null || clientChallenge + == null) + { + return null; + } + return NtlmPasswordAuthentication.GetLMv2Response(domain, user, password, type2.GetChallenge + (), clientChallenge); + } + + public static byte[] GetNtlMv2Response(Type2Message type2, byte[] responseKeyNt, + byte[] clientChallenge) + { + if (type2 == null || responseKeyNt == null || clientChallenge == null) + { + return null; + } + long nanos1601 = (Runtime.CurrentTimeMillis() + MillisecondsBetween1970And1601 + ) * 10000L; + return NtlmPasswordAuthentication.GetNtlMv2Response(responseKeyNt, type2.GetChallenge + (), clientChallenge, nanos1601, type2.GetTargetInformation()); + } + + /// <summary> + /// Constructs the NT response to the given Type-2 message using + /// the supplied password. + /// </summary> + /// <remarks> + /// Constructs the NT response to the given Type-2 message using + /// the supplied password. + /// </remarks> + /// <param name="type2">The Type-2 message.</param> + /// <param name="password">The password.</param> + /// <returns>A <code>byte[]</code> containing the NT response.</returns> + public static byte[] GetNTResponse(Type2Message type2, string password) + { + if (type2 == null || password == null) + { + return null; + } + return NtlmPasswordAuthentication.GetNtlmResponse(password, type2.GetChallenge()); + } + + /// <summary>Returns the default domain from the current environment.</summary> + /// <remarks>Returns the default domain from the current environment.</remarks> + /// <returns>The default domain.</returns> + public static string GetDefaultDomain() + { + return DefaultDomain; + } + + /// <summary>Returns the default user from the current environment.</summary> + /// <remarks>Returns the default user from the current environment.</remarks> + /// <returns>The default user.</returns> + public static string GetDefaultUser() + { + return DefaultUser; + } + + /// <summary>Returns the default password from the current environment.</summary> + /// <remarks>Returns the default password from the current environment.</remarks> + /// <returns>The default password.</returns> + public static string GetDefaultPassword() + { + return DefaultPassword; + } + + /// <summary>Returns the default workstation from the current environment.</summary> + /// <remarks>Returns the default workstation from the current environment.</remarks> + /// <returns>The default workstation.</returns> + public static string GetDefaultWorkstation() + { + return DefaultWorkstation; + } + + /// <exception cref="System.IO.IOException"></exception> + private void Parse(byte[] material) + { + for (int i = 0; i < 8; i++) + { + if (material[i] != NtlmsspSignature[i]) + { + throw new IOException("Not an NTLMSSP message."); + } + } + if (ReadULong(material, 8) != 3) + { + throw new IOException("Not a Type 3 message."); + } + byte[] lmResponse = ReadSecurityBuffer(material, 12); + int lmResponseOffset = ReadULong(material, 16); + byte[] ntResponse = ReadSecurityBuffer(material, 20); + int ntResponseOffset = ReadULong(material, 24); + byte[] domain = ReadSecurityBuffer(material, 28); + int domainOffset = ReadULong(material, 32); + byte[] user = ReadSecurityBuffer(material, 36); + int userOffset = ReadULong(material, 40); + byte[] workstation = ReadSecurityBuffer(material, 44); + int workstationOffset = ReadULong(material, 48); + int flags; + string charset; + byte[] _sessionKey = null; + if (lmResponseOffset == 52 || ntResponseOffset == 52 || domainOffset == 52 || userOffset + == 52 || workstationOffset == 52) + { + flags = NtlmsspNegotiateNtlm | NtlmsspNegotiateOem; + charset = GetOemEncoding(); + } + else + { + _sessionKey = ReadSecurityBuffer(material, 52); + flags = ReadULong(material, 60); + charset = ((flags & NtlmsspNegotiateUnicode) != 0) ? UniEncoding : GetOemEncoding + (); + } + SetSessionKey(_sessionKey); + SetFlags(flags); + SetLmResponse(lmResponse); + SetNtResponse(ntResponse); + SetDomain(Runtime.GetStringForBytes(domain, charset)); + SetUser(Runtime.GetStringForBytes(user, charset)); + SetWorkstation(Runtime.GetStringForBytes(workstation, charset)); + } + } +} |
