SessionSetupHelper.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 SMBLibrary.Authentication.GSSAPI;
  11. using SMBLibrary.Authentication.NTLM;
  12. using SMBLibrary.SMB1;
  13. using Utilities;
  14. namespace SMBLibrary.Server.SMB1
  15. {
  16. /// <summary>
  17. /// Session Setup helper
  18. /// </summary>
  19. public class SessionSetupHelper
  20. {
  21. internal static SMB1Command GetSessionSetupResponse(SMB1Header header, SessionSetupAndXRequest request, NTLMAuthenticationProviderBase securityProvider, SMB1ConnectionState state)
  22. {
  23. SessionSetupAndXResponse response = new SessionSetupAndXResponse();
  24. // The PrimaryDomain field in the request is used to determine with domain controller should authenticate the user credentials,
  25. // However, the domain controller itself does not use this field.
  26. // See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378749%28v=vs.85%29.aspx
  27. AuthenticateMessage message = CreateAuthenticateMessage(request.AccountName, request.OEMPassword, request.UnicodePassword);
  28. header.Status = securityProvider.Authenticate(state.AuthenticationContext, message);
  29. if (header.Status != NTStatus.STATUS_SUCCESS)
  30. {
  31. state.LogToServer(Severity.Information, "User '{0}' failed authentication, NTStatus: {1}", message.UserName, header.Status);
  32. return new ErrorResponse(request.CommandName);
  33. }
  34. bool? isGuest = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.IsGuest) as bool?;
  35. SMB1Session session;
  36. if (!isGuest.HasValue || !isGuest.Value)
  37. {
  38. state.LogToServer(Severity.Information, "User '{0}' authenticated successfully.", message.UserName);
  39. session = state.CreateSession(message.UserName, message.WorkStation);
  40. }
  41. else
  42. {
  43. state.LogToServer(Severity.Information, "User '{0}' failed authentication, logged in as guest.", message.UserName);
  44. session = state.CreateSession("Guest", message.WorkStation);
  45. response.Action = SessionSetupAction.SetupGuest;
  46. }
  47. if (session == null)
  48. {
  49. header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
  50. return new ErrorResponse(request.CommandName);
  51. }
  52. header.UID = session.UserID;
  53. response.PrimaryDomain = request.PrimaryDomain;
  54. if ((request.Capabilities & ServerCapabilities.LargeRead) > 0)
  55. {
  56. state.LargeRead = true;
  57. }
  58. if ((request.Capabilities & ServerCapabilities.LargeWrite) > 0)
  59. {
  60. state.LargeWrite = true;
  61. }
  62. response.NativeOS = String.Empty; // "Windows Server 2003 3790 Service Pack 2"
  63. response.NativeLanMan = String.Empty; // "Windows Server 2003 5.2"
  64. return response;
  65. }
  66. internal static SMB1Command GetSessionSetupResponseExtended(SMB1Header header, SessionSetupAndXRequestExtended request, NTLMAuthenticationProviderBase securityProvider, SMB1ConnectionState state)
  67. {
  68. SessionSetupAndXResponseExtended response = new SessionSetupAndXResponseExtended();
  69. // [MS-SMB] The Windows GSS implementation supports raw Kerberos / NTLM messages in the SecurityBlob
  70. byte[] messageBytes = request.SecurityBlob;
  71. bool isRawMessage = true;
  72. if (!AuthenticationMessageUtils.IsSignatureValid(messageBytes))
  73. {
  74. messageBytes = GSSAPIHelper.GetNTLMSSPMessage(request.SecurityBlob);
  75. isRawMessage = false;
  76. }
  77. if (!AuthenticationMessageUtils.IsSignatureValid(messageBytes))
  78. {
  79. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  80. return new ErrorResponse(request.CommandName);
  81. }
  82. // According to [MS-SMB] 3.3.5.3, a UID MUST be allocated if the server returns STATUS_MORE_PROCESSING_REQUIRED
  83. if (header.UID == 0)
  84. {
  85. ushort? userID = state.AllocateUserID();
  86. if (!userID.HasValue)
  87. {
  88. header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
  89. return new ErrorResponse(request.CommandName);
  90. }
  91. header.UID = userID.Value;
  92. }
  93. MessageTypeName messageType = AuthenticationMessageUtils.GetMessageType(messageBytes);
  94. if (messageType == MessageTypeName.Negotiate)
  95. {
  96. NegotiateMessage negotiateMessage = new NegotiateMessage(messageBytes);
  97. ChallengeMessage challengeMessage;
  98. NTStatus status = securityProvider.GetChallengeMessage(out state.AuthenticationContext, negotiateMessage, out challengeMessage);
  99. if (status != NTStatus.SEC_I_CONTINUE_NEEDED)
  100. {
  101. header.Status = status;
  102. return new ErrorResponse(request.CommandName);
  103. }
  104. if (isRawMessage)
  105. {
  106. response.SecurityBlob = challengeMessage.GetBytes();
  107. }
  108. else
  109. {
  110. response.SecurityBlob = GSSAPIHelper.GetGSSTokenResponseBytesFromNTLMSSPMessage(challengeMessage.GetBytes());
  111. }
  112. header.Status = NTStatus.STATUS_MORE_PROCESSING_REQUIRED;
  113. }
  114. else // MessageTypeName.Authenticate
  115. {
  116. AuthenticateMessage authenticateMessage = new AuthenticateMessage(messageBytes);
  117. header.Status = securityProvider.Authenticate(state.AuthenticationContext, authenticateMessage);
  118. if (header.Status != NTStatus.STATUS_SUCCESS)
  119. {
  120. state.LogToServer(Severity.Information, "User '{0}' failed authentication, NTStatus: {1}", authenticateMessage.UserName, header.Status);
  121. return new ErrorResponse(request.CommandName);
  122. }
  123. bool? isGuest = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.IsGuest) as bool?;
  124. if (!isGuest.HasValue || !isGuest.Value)
  125. {
  126. state.LogToServer(Severity.Information, "User '{0}' authenticated successfully.", authenticateMessage.UserName);
  127. state.CreateSession(header.UID, authenticateMessage.UserName, authenticateMessage.WorkStation);
  128. }
  129. else
  130. {
  131. state.LogToServer(Severity.Information, "User '{0}' failed authentication, logged in as guest.", authenticateMessage.UserName);
  132. state.CreateSession(header.UID, "Guest", authenticateMessage.WorkStation);
  133. response.Action = SessionSetupAction.SetupGuest;
  134. }
  135. if (!isRawMessage)
  136. {
  137. response.SecurityBlob = GSSAPIHelper.GetGSSTokenAcceptCompletedResponse();
  138. }
  139. }
  140. response.NativeOS = String.Empty; // "Windows Server 2003 3790 Service Pack 2"
  141. response.NativeLanMan = String.Empty; // "Windows Server 2003 5.2"
  142. return response;
  143. }
  144. private static AuthenticateMessage CreateAuthenticateMessage(string accountNameToAuth, byte[] lmChallengeResponse, byte[] ntChallengeResponse)
  145. {
  146. AuthenticateMessage authenticateMessage = new AuthenticateMessage();
  147. authenticateMessage.NegotiateFlags = NegotiateFlags.UnicodeEncoding |
  148. NegotiateFlags.OEMEncoding |
  149. NegotiateFlags.Sign |
  150. NegotiateFlags.LanManagerKey |
  151. NegotiateFlags.NTLMKey |
  152. NegotiateFlags.AlwaysSign |
  153. NegotiateFlags.Version |
  154. NegotiateFlags.Use128BitEncryption |
  155. NegotiateFlags.Use56BitEncryption;
  156. if (AuthenticationMessageUtils.IsNTLMv1ExtendedSecurity(lmChallengeResponse) ||
  157. AuthenticationMessageUtils.IsNTLMv2NTResponse(ntChallengeResponse))
  158. {
  159. authenticateMessage.NegotiateFlags |= NegotiateFlags.ExtendedSecurity;
  160. }
  161. authenticateMessage.UserName = accountNameToAuth;
  162. authenticateMessage.LmChallengeResponse = lmChallengeResponse;
  163. authenticateMessage.NtChallengeResponse = ntChallengeResponse;
  164. authenticateMessage.Version = NTLMVersion.Server2003;
  165. return authenticateMessage;
  166. }
  167. }
  168. }