IndependentUserCollection.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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[] ntlmResponse)
  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 = NTAuthentication.ComputeLMv1Response(serverChallenge, password);
  36. if (ByteUtils.AreByteArraysEqual(expectedLMResponse, lmResponse))
  37. {
  38. return this[index];
  39. }
  40. byte[] expectedNTLMResponse = NTAuthentication.ComputeNTLMv1Response(serverChallenge, password);
  41. if (ByteUtils.AreByteArraysEqual(expectedNTLMResponse, ntlmResponse))
  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[] ntlmResponse)
  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 = NTAuthentication.ComputeNTLMv1ExtendedSecurityResponse(serverChallenge, clientChallenge, password);
  62. if (ByteUtils.AreByteArraysEqual(expectedNTLMv1Response, ntlmResponse))
  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[] ntlmResponse)
  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 = NTAuthentication.ComputeLMv2Response(serverChallenge, _LMv2ClientChallenge, password, accountName, domainNameToAuth);
  83. if (ByteUtils.AreByteArraysEqual(expectedLMv2Response, lmResponse))
  84. {
  85. return this[index];
  86. }
  87. if (ntlmResponse.Length > 24)
  88. {
  89. NTLMv2ClientChallengeStructure clientChallengeStructure = new NTLMv2ClientChallengeStructure(ntlmResponse, 16);
  90. byte[] clientChallengeStructurePadded = clientChallengeStructure.GetBytesPadded();
  91. byte[] expectedNTLMv2Response = NTAuthentication.ComputeNTLMv2Response(serverChallenge, clientChallengeStructurePadded, password, accountName, domainNameToAuth);
  92. if (ByteUtils.AreByteArraysEqual(expectedNTLMv2Response, ntlmResponse))
  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.NegotiateUnicode |
  111. NegotiateFlags.RequestTarget |
  112. NegotiateFlags.NegotiateNTLMKey |
  113. NegotiateFlags.NegotiateExtendedSecurity |
  114. NegotiateFlags.NegotiateTargetInfo |
  115. NegotiateFlags.NegotiateVersion |
  116. NegotiateFlags.Negotiate128 |
  117. NegotiateFlags.Negotiate56;
  118. message.TargetName = Environment.MachineName;
  119. message.ServerChallenge = serverChallenge;
  120. message.TargetInfo = AVPairUtils.GetAVPairSequence(Environment.MachineName, Environment.MachineName);
  121. message.Version = Authentication.Version.Server2003;
  122. return message;
  123. }
  124. public bool Authenticate(AuthenticateMessage message)
  125. {
  126. if ((message.NegotiateFlags & NegotiateFlags.NegotiateAnonymous) > 0)
  127. {
  128. return this.EnableGuestLogin;
  129. }
  130. User user;
  131. if ((message.NegotiateFlags & NegotiateFlags.NegotiateExtendedSecurity) > 0)
  132. {
  133. user = AuthenticateV1Extended(message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
  134. if (user == null)
  135. {
  136. // NTLM v2:
  137. user = AuthenticateV2(message.DomainName, message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
  138. }
  139. }
  140. else
  141. {
  142. user = AuthenticateV1(message.UserName, m_serverChallenge, message.LmChallengeResponse, message.NtChallengeResponse);
  143. }
  144. return (user != null);
  145. }
  146. public bool FallbackToGuest(string userName)
  147. {
  148. return (EnableGuestLogin && (IndexOf(userName) == -1));
  149. }
  150. private bool EnableGuestLogin
  151. {
  152. get
  153. {
  154. int index = IndexOf("Guest");
  155. return (index >= 0 && this[index].Password == String.Empty);
  156. }
  157. }
  158. public byte[] ServerChallenge
  159. {
  160. get
  161. {
  162. return m_serverChallenge;
  163. }
  164. }
  165. }
  166. }