GSS-style authentication, additional IGSSMechanism implementations can be provided

This commit is contained in:
Tal Aloni 2017-02-18 16:10:03 +02:00
parent d4acf5900e
commit a84226abb9
11 changed files with 275 additions and 182 deletions

View file

@ -1,69 +0,0 @@
/* Copyright (C) 2017 Tal Aloni <tal.aloni.il@gmail.com>. 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.Authentication.GSSAPI
{
public class GSSAPIHelper
{
public static readonly byte[] NTLMSSPIdentifier = new byte[] { 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a };
/// <summary>
/// https://msdn.microsoft.com/en-us/library/ms995330.aspx
/// </summary>
public static byte[] GetNTLMSSPMessage(byte[] tokenBytes)
{
SimpleProtectedNegotiationToken token = SimpleProtectedNegotiationToken.ReadToken(tokenBytes, 0);
if (token != null)
{
if (token is SimpleProtectedNegotiationTokenInit)
{
SimpleProtectedNegotiationTokenInit tokenInit = (SimpleProtectedNegotiationTokenInit)token;
foreach (byte[] identifier in tokenInit.MechanismTypeList)
{
if (ByteUtils.AreByteArraysEqual(identifier, NTLMSSPIdentifier))
{
return tokenInit.MechanismToken;
}
}
}
else
{
SimpleProtectedNegotiationTokenResponse tokenResponse = (SimpleProtectedNegotiationTokenResponse)token;
return tokenResponse.ResponseToken;
}
}
return null;
}
public static byte[] GetGSSTokenInitNTLMSSPBytes()
{
SimpleProtectedNegotiationTokenInit token = new SimpleProtectedNegotiationTokenInit();
token.MechanismTypeList = new List<byte[]>();
token.MechanismTypeList.Add(NTLMSSPIdentifier);
return SimpleProtectedNegotiationToken.GetTokenBytes(token);
}
public static byte[] GetGSSTokenResponseBytesFromNTLMSSPMessage(byte[] messageBytes)
{
SimpleProtectedNegotiationTokenResponse token = new SimpleProtectedNegotiationTokenResponse();
token.NegState = NegState.AcceptIncomplete;
token.SupportedMechanism = NTLMSSPIdentifier;
token.ResponseToken = messageBytes;
return token.GetBytes();
}
public static byte[] GetGSSTokenAcceptCompletedResponse()
{
SimpleProtectedNegotiationTokenResponse token = new SimpleProtectedNegotiationTokenResponse();
token.NegState = NegState.AcceptCompleted;
return token.GetBytes();
}
}
}

View file

@ -0,0 +1,213 @@
/* Copyright (C) 2017 Tal Aloni <tal.aloni.il@gmail.com>. 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 SMBLibrary.Authentication.NTLM;
using Utilities;
namespace SMBLibrary.Authentication.GSSAPI
{
public class GSSProvider
{
public static readonly byte[] NTLMSSPIdentifier = new byte[] { 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a };
private List<IGSSMechanism> m_mechanisms;
private Dictionary<object, IGSSMechanism> m_contextToMechanism = new Dictionary<object, IGSSMechanism>();
public GSSProvider(IGSSMechanism mechanism)
{
m_mechanisms = new List<IGSSMechanism>();
m_mechanisms.Add(mechanism);
}
public GSSProvider(List<IGSSMechanism> mechanisms)
{
m_mechanisms = mechanisms;
}
public byte[] GetSPNEGOTokenInitBytes()
{
SimpleProtectedNegotiationTokenInit token = new SimpleProtectedNegotiationTokenInit();
token.MechanismTypeList = new List<byte[]>();
foreach (IGSSMechanism mechanism in m_mechanisms)
{
token.MechanismTypeList.Add(mechanism.Identifier);
}
return SimpleProtectedNegotiationToken.GetTokenBytes(token);
}
public NTStatus AcceptSecurityContext(ref object context, byte[] inputToken, out byte[] outputToken)
{
outputToken = null;
SimpleProtectedNegotiationToken spnegoToken = SimpleProtectedNegotiationToken.ReadToken(inputToken, 0);
if (spnegoToken != null)
{
if (spnegoToken is SimpleProtectedNegotiationTokenInit)
{
SimpleProtectedNegotiationTokenInit tokenInit = (SimpleProtectedNegotiationTokenInit)spnegoToken;
IGSSMechanism mechanism = FindMechanism(tokenInit.MechanismTypeList);
if (mechanism != null)
{
byte[] mechanismOutput;
NTStatus status = mechanism.AcceptSecurityContext(ref context, tokenInit.MechanismToken, out mechanismOutput);
outputToken = GetSPNEGOTokenResponseBytes(mechanismOutput, status, mechanism.Identifier);
m_contextToMechanism[context] = mechanism;
return status;
}
return NTStatus.SEC_E_SECPKG_NOT_FOUND;
}
else // SimpleProtectedNegotiationTokenResponse
{
IGSSMechanism mechanism;
if (!m_contextToMechanism.TryGetValue(context, out mechanism))
{
// We assume that the problem is not with our implementation and that the client has sent
// SimpleProtectedNegotiationTokenResponse without first sending SimpleProtectedNegotiationTokenInit.
return NTStatus.SEC_E_INVALID_TOKEN;
}
SimpleProtectedNegotiationTokenResponse tokenResponse = (SimpleProtectedNegotiationTokenResponse)spnegoToken;
byte[] mechanismOutput;
NTStatus status = mechanism.AcceptSecurityContext(ref context, tokenResponse.ResponseToken, out mechanismOutput);
outputToken = GetSPNEGOTokenResponseBytes(mechanismOutput, status, null);
return status;
}
}
else
{
// [MS-SMB] The Windows GSS implementation supports raw Kerberos / NTLM messages in the SecurityBlob.
// [MS-SMB2] Windows [..] will also accept raw Kerberos messages and implicit NTLM messages as part of GSS authentication.
if (AuthenticationMessageUtils.IsSignatureValid(inputToken))
{
MessageTypeName messageType = AuthenticationMessageUtils.GetMessageType(inputToken);
IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier);
if (ntlmAuthenticationProvider != null)
{
NTStatus status = ntlmAuthenticationProvider.AcceptSecurityContext(ref context, inputToken, out outputToken);
if (messageType == MessageTypeName.Negotiate)
{
m_contextToMechanism[context] = ntlmAuthenticationProvider;
}
return status;
}
else
{
return NTStatus.SEC_E_SECPKG_NOT_FOUND;
}
}
}
return NTStatus.SEC_E_INVALID_TOKEN;
}
public object GetContextAttribute(object context, GSSAttributeName attributeName)
{
IGSSMechanism mechanism;
if (!m_contextToMechanism.TryGetValue(context, out mechanism))
{
return null;
}
return mechanism.GetContextAttribute(context, attributeName);
}
public void DeleteSecurityContext(ref object context)
{
if (context != null)
{
IGSSMechanism mechanism;
if (m_contextToMechanism.TryGetValue(context, out mechanism))
{
mechanism.DeleteSecurityContext(ref context);
m_contextToMechanism.Remove(context);
}
}
}
/// <summary>
/// Helper method for legacy implementation.
/// </summary>
public NTStatus GetNTLMChallengeMessage(out object context, NegotiateMessage negotiateMessage, out ChallengeMessage challengeMessage)
{
context = null;
challengeMessage = null;
IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier);
if (ntlmAuthenticationProvider != null)
{
byte[] outputToken;
NTStatus result = ntlmAuthenticationProvider.AcceptSecurityContext(ref context, negotiateMessage.GetBytes(), out outputToken);
challengeMessage = new ChallengeMessage(outputToken);
m_contextToMechanism.Add(context, ntlmAuthenticationProvider);
return result;
}
else
{
return NTStatus.SEC_E_SECPKG_NOT_FOUND;
}
}
/// <summary>
/// Helper method for legacy implementation.
/// </summary>
public NTStatus NTLMAuthenticate(object context, AuthenticateMessage authenticateMessage)
{
IGSSMechanism ntlmAuthenticationProvider = FindMechanism(NTLMSSPIdentifier);
if (ntlmAuthenticationProvider != null)
{
byte[] outputToken;
NTStatus result = ntlmAuthenticationProvider.AcceptSecurityContext(ref context, authenticateMessage.GetBytes(), out outputToken);
return result;
}
else
{
return NTStatus.SEC_E_SECPKG_NOT_FOUND;
}
}
public IGSSMechanism FindMechanism(List<byte[]> mechanismIdentifiers)
{
foreach (byte[] identifier in mechanismIdentifiers)
{
IGSSMechanism mechanism = FindMechanism(identifier);
if (mechanism != null)
{
return mechanism;
}
}
return null;
}
public IGSSMechanism FindMechanism(byte[] mechanismIdentifier)
{
foreach (IGSSMechanism mechanism in m_mechanisms)
{
if (ByteUtils.AreByteArraysEqual(mechanism.Identifier, mechanismIdentifier))
{
return mechanism;
}
}
return null;
}
private static byte[] GetSPNEGOTokenResponseBytes(byte[] mechanismOutput, NTStatus status, byte[] mechanismIdentifier)
{
SimpleProtectedNegotiationTokenResponse tokenResponse = new SimpleProtectedNegotiationTokenResponse();
if (status == NTStatus.STATUS_SUCCESS)
{
tokenResponse.NegState = NegState.AcceptCompleted;
}
else if (status == NTStatus.SEC_I_CONTINUE_NEEDED)
{
tokenResponse.NegState = NegState.AcceptIncomplete;
}
else
{
tokenResponse.NegState = NegState.Reject;
}
tokenResponse.SupportedMechanism = mechanismIdentifier;
tokenResponse.ResponseToken = mechanismOutput;
return tokenResponse.GetBytes();
}
}
}

View file

@ -7,6 +7,7 @@ namespace SMBLibrary
SEC_I_CONTINUE_NEEDED = 0x00090312,
STATUS_OBJECT_NAME_EXISTS = 0x40000000,
STATUS_NO_MORE_FILES = 0x80000006,
SEC_E_SECPKG_NOT_FOUND = 0x80090305,
SEC_E_INVALID_TOKEN = 0x80090308,
STATUS_NOT_IMPLEMENTED = 0xC0000002,
STATUS_INVALID_INFO_CLASS = 0xC0000003,

View file

@ -32,7 +32,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Authentication\GSSAPI\Enums\GSSAttributeName.cs" />
<Compile Include="Authentication\GSSAPI\GSSAPIHelper.cs" />
<Compile Include="Authentication\GSSAPI\GSSProvider.cs" />
<Compile Include="Authentication\GSSAPI\IGSSMechanism.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\DerEncodingHelper.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationToken.cs" />

View file

@ -7,7 +7,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using SMBLibrary.Authentication;
using SMBLibrary.Authentication.GSSAPI;
using SMBLibrary.Authentication.NTLM;
using SMBLibrary.SMB1;
using Utilities;
@ -19,7 +19,7 @@ namespace SMBLibrary.Server.SMB1
/// </summary>
public class NegotiateHelper
{
internal static NegotiateResponseNTLM GetNegotiateResponse(SMB1Header header, NegotiateRequest request, NTLMAuthenticationProviderBase securityProvider, ConnectionState state)
internal static NegotiateResponseNTLM GetNegotiateResponse(SMB1Header header, NegotiateRequest request, GSSProvider securityProvider, ConnectionState state)
{
NegotiateResponseNTLM response = new NegotiateResponseNTLM();
@ -40,7 +40,7 @@ namespace SMBLibrary.Server.SMB1
response.ServerTimeZone = (short)-TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).TotalMinutes;
NegotiateMessage negotiateMessage = CreateNegotiateMessage();
ChallengeMessage challengeMessage;
NTStatus status = securityProvider.GetChallengeMessage(out state.AuthenticationContext, negotiateMessage, out challengeMessage);
NTStatus status = securityProvider.GetNTLMChallengeMessage(out state.AuthenticationContext, negotiateMessage, out challengeMessage);
if (status == NTStatus.SEC_I_CONTINUE_NEEDED)
{
response.Challenge = challengeMessage.ServerChallenge;

View file

@ -19,14 +19,14 @@ namespace SMBLibrary.Server.SMB1
/// </summary>
public class SessionSetupHelper
{
internal static SMB1Command GetSessionSetupResponse(SMB1Header header, SessionSetupAndXRequest request, NTLMAuthenticationProviderBase securityProvider, SMB1ConnectionState state)
internal static SMB1Command GetSessionSetupResponse(SMB1Header header, SessionSetupAndXRequest request, GSSProvider securityProvider, SMB1ConnectionState state)
{
SessionSetupAndXResponse response = new SessionSetupAndXResponse();
// The PrimaryDomain field in the request is used to determine with domain controller should authenticate the user credentials,
// However, the domain controller itself does not use this field.
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378749%28v=vs.85%29.aspx
AuthenticateMessage message = CreateAuthenticateMessage(request.AccountName, request.OEMPassword, request.UnicodePassword);
header.Status = securityProvider.Authenticate(state.AuthenticationContext, message);
header.Status = securityProvider.NTLMAuthenticate(state.AuthenticationContext, message);
if (header.Status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Information, "User '{0}' failed authentication, NTStatus: {1}", message.UserName, header.Status);
@ -69,24 +69,26 @@ namespace SMBLibrary.Server.SMB1
return response;
}
internal static SMB1Command GetSessionSetupResponseExtended(SMB1Header header, SessionSetupAndXRequestExtended request, NTLMAuthenticationProviderBase securityProvider, SMB1ConnectionState state)
internal static SMB1Command GetSessionSetupResponseExtended(SMB1Header header, SessionSetupAndXRequestExtended request, GSSProvider securityProvider, SMB1ConnectionState state)
{
SessionSetupAndXResponseExtended response = new SessionSetupAndXResponseExtended();
// [MS-SMB] The Windows GSS implementation supports raw Kerberos / NTLM messages in the SecurityBlob
byte[] messageBytes = request.SecurityBlob;
bool isRawMessage = true;
if (!AuthenticationMessageUtils.IsSignatureValid(messageBytes))
byte[] outputToken;
NTStatus status = securityProvider.AcceptSecurityContext(ref state.AuthenticationContext, request.SecurityBlob, out outputToken);
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.SEC_I_CONTINUE_NEEDED)
{
messageBytes = GSSAPIHelper.GetNTLMSSPMessage(request.SecurityBlob);
isRawMessage = false;
}
if (!AuthenticationMessageUtils.IsSignatureValid(messageBytes))
{
header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
string userName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.UserName) as string;
state.LogToServer(Severity.Information, "User '{0}' failed authentication, NTStatus: {1}", userName, status);
header.Status = status;
return new ErrorResponse(request.CommandName);
}
if (outputToken != null)
{
response.SecurityBlob = outputToken;
}
// According to [MS-SMB] 3.3.5.3, a UID MUST be allocated if the server returns STATUS_MORE_PROCESSING_REQUIRED
if (header.UID == 0)
{
@ -99,55 +101,26 @@ namespace SMBLibrary.Server.SMB1
header.UID = userID.Value;
}
MessageTypeName messageType = AuthenticationMessageUtils.GetMessageType(messageBytes);
if (messageType == MessageTypeName.Negotiate)
if (status == NTStatus.SEC_I_CONTINUE_NEEDED)
{
NegotiateMessage negotiateMessage = new NegotiateMessage(messageBytes);
ChallengeMessage challengeMessage;
NTStatus status = securityProvider.GetChallengeMessage(out state.AuthenticationContext, negotiateMessage, out challengeMessage);
if (status != NTStatus.SEC_I_CONTINUE_NEEDED)
{
header.Status = status;
return new ErrorResponse(request.CommandName);
}
if (isRawMessage)
{
response.SecurityBlob = challengeMessage.GetBytes();
}
else
{
response.SecurityBlob = GSSAPIHelper.GetGSSTokenResponseBytesFromNTLMSSPMessage(challengeMessage.GetBytes());
}
header.Status = NTStatus.STATUS_MORE_PROCESSING_REQUIRED;
}
else // MessageTypeName.Authenticate
else // header.Status == NTStatus.STATUS_SUCCESS
{
AuthenticateMessage authenticateMessage = new AuthenticateMessage(messageBytes);
header.Status = securityProvider.Authenticate(state.AuthenticationContext, authenticateMessage);
if (header.Status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Information, "User '{0}' failed authentication, NTStatus: {1}", authenticateMessage.UserName, header.Status);
return new ErrorResponse(request.CommandName);
}
string userName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.UserName) as string;
string machineName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.MachineName) as string;
bool? isGuest = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.IsGuest) as bool?;
if (!isGuest.HasValue || !isGuest.Value)
{
state.LogToServer(Severity.Information, "User '{0}' authenticated successfully.", authenticateMessage.UserName);
state.CreateSession(header.UID, authenticateMessage.UserName, authenticateMessage.WorkStation);
state.LogToServer(Severity.Information, "User '{0}' authenticated successfully.", userName);
state.CreateSession(header.UID, userName, machineName);
}
else
{
state.LogToServer(Severity.Information, "User '{0}' failed authentication, logged in as guest.", authenticateMessage.UserName);
state.CreateSession(header.UID, "Guest", authenticateMessage.WorkStation);
state.LogToServer(Severity.Information, "User '{0}' failed authentication, logged in as guest.", userName);
state.CreateSession(header.UID, "Guest", machineName);
response.Action = SessionSetupAction.SetupGuest;
}
if (!isRawMessage)
{
response.SecurityBlob = GSSAPIHelper.GetGSSTokenAcceptCompletedResponse();
}
}
response.NativeOS = String.Empty; // "Windows Server 2003 3790 Service Pack 2"
response.NativeLanMan = String.Empty; // "Windows Server 2003 5.2"

View file

@ -21,7 +21,7 @@ namespace SMBLibrary.Server.SMB2
public const string SMB2xxxDialect = "SMB 2.???";
// Special case - SMB2 client initially connecting using SMB1
internal static SMB2Command GetNegotiateResponse(List<string> smb2Dialects, ConnectionState state, Guid serverGuid)
internal static SMB2Command GetNegotiateResponse(List<string> smb2Dialects, GSSProvider securityProvider, ConnectionState state, Guid serverGuid)
{
NegotiateResponse response = new NegotiateResponse();
response.Header.Credits = 1;
@ -45,11 +45,11 @@ namespace SMBLibrary.Server.SMB2
response.MaxWriteSize = 65536;
response.SystemTime = DateTime.Now;
response.ServerStartTime = DateTime.Today;
response.SecurityBuffer = GSSAPIHelper.GetGSSTokenInitNTLMSSPBytes();
response.SecurityBuffer = securityProvider.GetSPNEGOTokenInitBytes();
return response;
}
internal static SMB2Command GetNegotiateResponse(NegotiateRequest request, ConnectionState state, Guid serverGuid)
internal static SMB2Command GetNegotiateResponse(NegotiateRequest request, GSSProvider securityProvider, ConnectionState state, Guid serverGuid)
{
NegotiateResponse response = new NegotiateResponse();
if (request.Dialects.Contains(SMB2Dialect.SMB210))
@ -72,7 +72,7 @@ namespace SMBLibrary.Server.SMB2
response.MaxWriteSize = 65536;
response.SystemTime = DateTime.Now;
response.ServerStartTime = DateTime.Today;
response.SecurityBuffer = GSSAPIHelper.GetGSSTokenInitNTLMSSPBytes();
response.SecurityBuffer = securityProvider.GetSPNEGOTokenInitBytes();
return response;
}

View file

@ -18,20 +18,22 @@ namespace SMBLibrary.Server.SMB2
/// </summary>
public class SessionSetupHelper
{
internal static SMB2Command GetSessionSetupResponse(SessionSetupRequest request, NTLMAuthenticationProviderBase securityProvider, SMB2ConnectionState state)
internal static SMB2Command GetSessionSetupResponse(SessionSetupRequest request, GSSProvider securityProvider, SMB2ConnectionState state)
{
// [MS-SMB2] Windows [..] will also accept raw Kerberos messages and implicit NTLM messages as part of GSS authentication.
SessionSetupResponse response = new SessionSetupResponse();
byte[] messageBytes = request.SecurityBuffer;
bool isRawMessage = true;
if (!AuthenticationMessageUtils.IsSignatureValid(messageBytes))
byte[] outputToken;
NTStatus status = securityProvider.AcceptSecurityContext(ref state.AuthenticationContext, request.SecurityBuffer, out outputToken);
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.SEC_I_CONTINUE_NEEDED)
{
messageBytes = GSSAPIHelper.GetNTLMSSPMessage(request.SecurityBuffer);
isRawMessage = false;
string userName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.UserName) as string;
state.LogToServer(Severity.Information, "User '{0}' failed authentication, NTStatus: {1}", userName, status);
return new ErrorResponse(request.CommandName, status);
}
if (!AuthenticationMessageUtils.IsSignatureValid(messageBytes))
if (outputToken != null)
{
return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED);
response.SecurityBuffer = outputToken;
}
// According to [MS-SMB2] 3.3.5.5.3, response.Header.SessionID must be allocated if the server returns STATUS_MORE_PROCESSING_REQUIRED
@ -45,54 +47,26 @@ namespace SMBLibrary.Server.SMB2
response.Header.SessionID = sessionID.Value;
}
MessageTypeName messageType = AuthenticationMessageUtils.GetMessageType(messageBytes);
if (messageType == MessageTypeName.Negotiate)
if (status == NTStatus.SEC_I_CONTINUE_NEEDED)
{
NegotiateMessage negotiateMessage = new NegotiateMessage(messageBytes);
ChallengeMessage challengeMessage;
NTStatus status = securityProvider.GetChallengeMessage(out state.AuthenticationContext, negotiateMessage, out challengeMessage);
if (status != NTStatus.SEC_I_CONTINUE_NEEDED)
{
return new ErrorResponse(request.CommandName, status);
}
if (isRawMessage)
{
response.SecurityBuffer = challengeMessage.GetBytes();
}
else
{
response.SecurityBuffer = GSSAPIHelper.GetGSSTokenResponseBytesFromNTLMSSPMessage(challengeMessage.GetBytes());
}
response.Header.Status = NTStatus.STATUS_MORE_PROCESSING_REQUIRED;
}
else // MessageTypeName.Authenticate
else // status == STATUS_SUCCESS
{
AuthenticateMessage authenticateMessage = new AuthenticateMessage(messageBytes);
NTStatus loginStatus = securityProvider.Authenticate(state.AuthenticationContext, authenticateMessage);
if (loginStatus != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Information, "User '{0}' failed authentication, NTStatus: {1}", authenticateMessage.UserName, loginStatus);
return new ErrorResponse(request.CommandName, loginStatus);
}
string userName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.UserName) as string;
string machineName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.MachineName) as string;
bool? isGuest = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.IsGuest) as bool?;
if (!isGuest.HasValue || !isGuest.Value)
{
state.LogToServer(Severity.Information, "User '{0}' authenticated successfully.", authenticateMessage.UserName);
state.CreateSession(request.Header.SessionID, authenticateMessage.UserName, authenticateMessage.WorkStation);
state.LogToServer(Severity.Information, "User '{0}' authenticated successfully.", userName);
state.CreateSession(request.Header.SessionID, userName, machineName);
}
else
{
state.LogToServer(Severity.Information, "User '{0}' failed authentication, logged in as guest.", authenticateMessage.UserName);
state.CreateSession(request.Header.SessionID, "Guest", authenticateMessage.WorkStation);
state.LogToServer(Severity.Information, "User '{0}' failed authentication, logged in as guest.", userName);
state.CreateSession(request.Header.SessionID, "Guest", machineName);
response.SessionFlags = SessionFlags.IsGuest;
}
if (!isRawMessage)
{
response.SecurityBuffer = GSSAPIHelper.GetGSSTokenAcceptCompletedResponse();
}
}
return response;
}

View file

@ -74,7 +74,7 @@ namespace SMBLibrary.Server
if (command is NegotiateRequest)
{
NegotiateRequest request = (NegotiateRequest)command;
SMB2Command response = NegotiateHelper.GetNegotiateResponse(request, state, m_serverGuid);
SMB2Command response = NegotiateHelper.GetNegotiateResponse(request, m_securityProvider, state, m_serverGuid);
if (state.ServerDialect != SMBDialect.NotSet)
{
state = new SMB2ConnectionState(state, AllocatePersistentFileID);

View file

@ -8,7 +8,7 @@ using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using SMBLibrary.Authentication.NTLM;
using SMBLibrary.Authentication.GSSAPI;
using SMBLibrary.NetBios;
using SMBLibrary.Services;
using SMBLibrary.SMB1;
@ -25,7 +25,7 @@ namespace SMBLibrary.Server
public const bool EnableExtendedSecurity = true;
private ShareCollection m_shares; // e.g. Shared folders
private NTLMAuthenticationProviderBase m_securityProvider;
private GSSProvider m_securityProvider;
private NamedPipeShare m_services; // Named pipes
private IPAddress m_serverAddress;
private SMBTransportType m_transport;
@ -38,11 +38,11 @@ namespace SMBLibrary.Server
public event EventHandler<LogEntry> OnLogEntry;
public SMBServer(ShareCollection shares, NTLMAuthenticationProviderBase securityProvider, IPAddress serverAddress, SMBTransportType transport) : this(shares, securityProvider, serverAddress, transport, true, true)
public SMBServer(ShareCollection shares, GSSProvider securityProvider, IPAddress serverAddress, SMBTransportType transport) : this(shares, securityProvider, serverAddress, transport, true, true)
{
}
public SMBServer(ShareCollection shares, NTLMAuthenticationProviderBase securityProvider, IPAddress serverAddress, SMBTransportType transport, bool enableSMB1, bool enableSMB2)
public SMBServer(ShareCollection shares, GSSProvider securityProvider, IPAddress serverAddress, SMBTransportType transport, bool enableSMB1, bool enableSMB2)
{
m_shares = shares;
m_securityProvider = securityProvider;
@ -245,7 +245,7 @@ namespace SMBLibrary.Server
List<string> smb2Dialects = SMB2.NegotiateHelper.FindSMB2Dialects(message);
if (smb2Dialects.Count > 0)
{
SMB2Command response = SMB2.NegotiateHelper.GetNegotiateResponse(smb2Dialects, state, m_serverGuid);
SMB2Command response = SMB2.NegotiateHelper.GetNegotiateResponse(smb2Dialects, m_securityProvider, state, m_serverGuid);
if (state.ServerDialect != SMBDialect.NotSet)
{
state = new SMB2ConnectionState(state, AllocatePersistentFileID);

View file

@ -17,6 +17,7 @@ using System.Text;
using System.Windows.Forms;
using System.Xml;
using SMBLibrary;
using SMBLibrary.Authentication.GSSAPI;
using SMBLibrary.Authentication.NTLM;
using SMBLibrary.Server;
using SMBLibrary.Win32.Security;
@ -62,11 +63,10 @@ namespace SMBServer
transportType = SMBTransportType.DirectTCPTransport;
}
NTLMAuthenticationProviderBase provider;
NTLMAuthenticationProviderBase authenticationMechanism;
if (chkIntegratedWindowsAuthentication.Checked)
{
provider = new IntegratedNTLMAuthenticationProvider();
authenticationMechanism = new IntegratedNTLMAuthenticationProvider();
}
else
{
@ -81,7 +81,7 @@ namespace SMBServer
return;
}
provider = new IndependentNTLMAuthenticationProvider(users.GetUserPassword);
authenticationMechanism = new IndependentNTLMAuthenticationProvider(users.GetUserPassword);
}
@ -96,7 +96,8 @@ namespace SMBServer
return;
}
m_server = new SMBLibrary.Server.SMBServer(shares, provider, serverAddress, transportType, chkSMB1.Checked, chkSMB2.Checked);
GSSProvider securityProvider = new GSSProvider(authenticationMechanism);
m_server = new SMBLibrary.Server.SMBServer(shares, securityProvider, serverAddress, transportType, chkSMB1.Checked, chkSMB2.Checked);
m_server.OnLogEntry += new EventHandler<LogEntry>(Server_OnLogEntry);
try