IndependentUserCollection.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. using Utilities;
  11. using SMBLibrary.Authentication;
  12. namespace SMBLibrary.Server
  13. {
  14. public class IndependentUserCollection : UserCollection, INTLMAuthenticationProvider
  15. {
  16. private byte[] m_serverChallenge = new byte[8];
  17. public IndependentUserCollection()
  18. {
  19. }
  20. public IndependentUserCollection(UserCollection users)
  21. {
  22. this.AddRange(users);
  23. }
  24. /// <summary>
  25. /// LM v1 / NTLM v1
  26. /// </summary>
  27. private User AuthenticateV1(string accountNameToAuth, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse)
  28. {
  29. for (int index = 0; index < this.Count; index++)
  30. {
  31. string accountName = this[index].AccountName;
  32. string password = this[index].Password;
  33. if (String.Equals(accountName, accountNameToAuth, StringComparison.InvariantCultureIgnoreCase))
  34. {
  35. byte[] expectedLMResponse = NTLMCryptography.ComputeLMv1Response(serverChallenge, password);
  36. if (ByteUtils.AreByteArraysEqual(expectedLMResponse, lmResponse))
  37. {
  38. return this[index];
  39. }
  40. byte[] expectedNTResponse = NTLMCryptography.ComputeNTLMv1Response(serverChallenge, password);
  41. if (ByteUtils.AreByteArraysEqual(expectedNTResponse, ntResponse))
  42. {
  43. return this[index];
  44. }
  45. }
  46. }
  47. return null;
  48. }
  49. /// <summary>
  50. /// LM v1 / NTLM v1 Extended Security
  51. /// </summary>
  52. private User AuthenticateV1Extended(string accountNameToAuth, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse)
  53. {
  54. for (int index = 0; index < this.Count; index++)
  55. {
  56. string accountName = this[index].AccountName;
  57. string password = this[index].Password;
  58. if (String.Equals(accountName, accountNameToAuth, StringComparison.InvariantCultureIgnoreCase))
  59. {
  60. byte[] clientChallenge = ByteReader.ReadBytes(lmResponse, 0, 8);
  61. byte[] expectedNTLMv1Response = NTLMCryptography.ComputeNTLMv1ExtendedSecurityResponse(serverChallenge, clientChallenge, password);
  62. if (ByteUtils.AreByteArraysEqual(expectedNTLMv1Response, ntResponse))
  63. {
  64. return this[index];
  65. }
  66. }
  67. }
  68. return null;
  69. }
  70. /// <summary>
  71. /// LM v2 / NTLM v2
  72. /// </summary>
  73. private User AuthenticateV2(string domainNameToAuth, string accountNameToAuth, byte[] serverChallenge, byte[] lmResponse, byte[] ntResponse)
  74. {
  75. for (int index = 0; index < this.Count; index++)
  76. {
  77. string accountName = this[index].AccountName;
  78. string password = this[index].Password;
  79. if (String.Equals(accountName, accountNameToAuth, StringComparison.InvariantCultureIgnoreCase))
  80. {
  81. byte[] _LMv2ClientChallenge = ByteReader.ReadBytes(lmResponse, 16, 8);
  82. byte[] expectedLMv2Response = NTLMCryptography.ComputeLMv2Response(serverChallenge, _LMv2ClientChallenge, password, accountName, domainNameToAuth);
  83. if (ByteUtils.AreByteArraysEqual(expectedLMv2Response, lmResponse))
  84. {
  85. return this[index];
  86. }
  87. if (AuthenticationMessageUtils.IsNTLMv2NTResponse(ntResponse))
  88. {
  89. byte[] clientNTProof = ByteReader.ReadBytes(ntResponse, 0, 16);
  90. byte[] clientChallengeStructurePadded = ByteReader.ReadBytes(ntResponse, 16, ntResponse.Length - 16);
  91. byte[] expectedNTProof = NTLMCryptography.ComputeNTLMv2Proof(serverChallenge, clientChallengeStructurePadded, password, accountName, domainNameToAuth);
  92. if (ByteUtils.AreByteArraysEqual(clientNTProof, expectedNTProof))
  93. {
  94. return this[index];
  95. }
  96. }
  97. }
  98. }
  99. return null;
  100. }
  101. private byte[] GenerateServerChallenge()
  102. {
  103. new Random().NextBytes(m_serverChallenge);
  104. return m_serverChallenge;
  105. }
  106. public ChallengeMessage GetChallengeMessage(NegotiateMessage negotiateMessage)
  107. {
  108. byte[] serverChallenge = GenerateServerChallenge();
  109. ChallengeMessage message = new ChallengeMessage();
  110. message.NegotiateFlags = NegotiateFlags.UnicodeEncoding |
  111. NegotiateFlags.TargetNameSupplied |
  112. NegotiateFlags.NTLMKey |
  113. NegotiateFlags.TargetTypeServer |
  114. NegotiateFlags.ExtendedSecurity |
  115. NegotiateFlags.TargetInfo |
  116. NegotiateFlags.Version;
  117. if ((negotiateMessage.NegotiateFlags & NegotiateFlags.Sign) > 0)
  118. {
  119. // [MS-NLMP] If the client sends NTLMSSP_NEGOTIATE_SIGN to the server in the NEGOTIATE_MESSAGE,
  120. // the server MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE.
  121. message.NegotiateFlags |= NegotiateFlags.Sign;
  122. }
  123. if ((negotiateMessage.NegotiateFlags & NegotiateFlags.Use56BitEncryption) > 0)
  124. {
  125. message.NegotiateFlags |= NegotiateFlags.Use56BitEncryption;
  126. }
  127. if ((negotiateMessage.NegotiateFlags & NegotiateFlags.Use128BitEncryption) > 0)
  128. {
  129. message.NegotiateFlags |= NegotiateFlags.Use128BitEncryption;
  130. }
  131. message.TargetName = Environment.MachineName;
  132. message.ServerChallenge = serverChallenge;
  133. message.TargetInfo = AVPairUtils.GetAVPairSequence(Environment.MachineName, Environment.MachineName);
  134. message.Version = NTLMVersion.Server2003;
  135. return message;
  136. }
  137. public bool Authenticate(AuthenticateMessage message)
  138. {
  139. if ((message.NegotiateFlags & NegotiateFlags.Anonymous) > 0)
  140. {
  141. return this.EnableGuestLogin;
  142. }
  143. User user;
  144. if ((message.NegotiateFlags & NegotiateFlags.ExtendedSecurity) > 0)
  145. {
  146. if (AuthenticationMessageUtils.IsNTLMv1ExtendedSecurity(message.LmChallengeResponse))
  147. {
  148. // NTLM v1 Extended Security:
  149. user = AuthenticateV1Extended(message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
  150. }
  151. else
  152. {
  153. // NTLM v2:
  154. user = AuthenticateV2(message.DomainName, message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
  155. }
  156. }
  157. else
  158. {
  159. user = AuthenticateV1(message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
  160. }
  161. return (user != null);
  162. }
  163. public bool FallbackToGuest(string userName)
  164. {
  165. return (EnableGuestLogin && (IndexOf(userName) == -1));
  166. }
  167. private bool EnableGuestLogin
  168. {
  169. get
  170. {
  171. int index = IndexOf("Guest");
  172. return (index >= 0 && this[index].Password == String.Empty);
  173. }
  174. }
  175. public byte[] ServerChallenge
  176. {
  177. get
  178. {
  179. return m_serverChallenge;
  180. }
  181. }
  182. }
  183. }