in ProtoSDK/MS-CIFS/Server/CifsServerContext.cs [666:1311]
protected virtual void UpdateResponseRoleContext(
CifsServerPerConnection connection,
SmbPacket requestPacket,
SmbPacket responsePacket)
{
if (requestPacket == null || responsePacket == null || responsePacket.SmbHeader.Status != 0)
{
return;
}
SmbHeader smbHeader = responsePacket.SmbHeader;
switch (responsePacket.SmbHeader.Command)
{
#region Negotiate
case SmbCommand.SMB_COM_NEGOTIATE:
{
SmbNegotiateRequestPacket request = requestPacket as SmbNegotiateRequestPacket;
SmbNegotiateResponsePacket response = responsePacket as SmbNegotiateResponsePacket;
if (request != null && response != null && request.SmbData.Dialects != null)
{
int dialectIndex = (int)(response.SmbParameters.DialectIndex);
byte[] dialectBytes = request.SmbData.Dialects;
int startIndex = 0;
for (int i = 0; i < dialectIndex; i++)
{
startIndex = Array.IndexOf<byte>(dialectBytes, 0, startIndex,
dialectBytes.Length - startIndex) + 1;
}
connection.SelectedDialect = CifsMessageUtils.ToSmbString(dialectBytes, startIndex, true);
connection.NTLMChallenge = response.SmbData.Challenge;
connection.OpLockSupport = this.opLockSupport;
connection.NegotiateTime = response.SmbParameters.SystemTime;
if (this.ntlmAuthenticationPolicy != NTLMAuthenticationPolicyValues.Disabled)
{
//Prepare security context for the coming ntlm authentication.
foreach (AccountCredential accountCredential in this.accountCredentials)
{
NlmpServerSecurityContext serverSecurityContext = new NlmpServerSecurityContext(
NegotiateTypes.NTLM_NEGOTIATE_OEM | NegotiateTypes.NTLMSSP_NEGOTIATE_NTLM,
new NlmpClientCredential(string.Empty, accountCredential.DomainName,
accountCredential.AccountName, accountCredential.Password),
!string.IsNullOrEmpty(this.domainName),
this.domainName,
this.serverName);
serverSecurityContext.UpdateServerChallenge(
BitConverter.ToUInt64(response.SmbData.Challenge, 0));
this.nlmpServerSecurityContexts.Add(serverSecurityContext);
}
}
if ((response.SmbParameters.SecurityMode & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
== SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
{
connection.IsSigningActive = true;
}
}
}
break;
#endregion
#region Session
case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
#region SMB_COM_SESSION_SETUP_ANDX
{
SmbSessionSetupAndxRequestPacket request = requestPacket as SmbSessionSetupAndxRequestPacket;
SmbSessionSetupAndxResponsePacket response = responsePacket as SmbSessionSetupAndxResponsePacket;
if (request != null && response != null)
{
NlmpServerSecurityContext securityContext = null;
if (response.SmbParameters.Action != ActionValues.GuestAccess)
{
this.ActiveAccount = CifsMessageUtils.PlainTextAuthenticate(request, this.accountCredentials);
if (string.IsNullOrEmpty(this.ActiveAccount))
{
securityContext = CifsMessageUtils.NTLMAuthenticate(request,
this.nlmpServerSecurityContexts, connection.NegotiateTime.Time);
if (securityContext != null)
{
connection.IsSigningActive = true;
connection.SigningChallengeResponse = request.SmbData.UnicodePassword;
this.ActiveAccount = securityContext.Context.ClientCredential.AccountName;
connection.SigningSessionKey = NlmpUtility.GetResponseKeyNt(
NlmpVersion.v1,
securityContext.Context.ClientCredential.DomainName,
securityContext.Context.ClientCredential.AccountName,
securityContext.Context.ClientCredential.Password);
}
}
}
CifsServerPerSession session = new CifsServerPerSession(
connection,
smbHeader.Uid,
securityContext,
DateTime.Now,
DateTime.Now,
CifsMessageUtils.ToSmbString(request.SmbData.AccountName, 0, false),
GenerateSessionGlobalId());
this.AddSession(session);
}
}
#endregion
break;
case SmbCommand.SMB_COM_LOGOFF_ANDX:
#region SMB_COM_LOGOFF_ANDX
{
SmbLogoffAndxRequestPacket request = requestPacket as SmbLogoffAndxRequestPacket;
SmbLogoffAndxResponsePacket response = responsePacket as SmbLogoffAndxResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
this.RemoveSession(session.SessionGlobalId);
}
}
#endregion
break;
#endregion
#region Tree Connect
case SmbCommand.SMB_COM_TREE_CONNECT:
#region SMB_COM_TREE_CONNECT
{
SmbTreeConnectRequestPacket request = requestPacket as SmbTreeConnectRequestPacket;
SmbTreeConnectResponsePacket response = responsePacket as SmbTreeConnectResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
//If Core Protocol, No sessions setup, make a default session
if (session == null
&& (connection.SelectedDialect == CifsMessageUtils.DIALECT_PCNETWORK_PROGRAM
|| connection.SelectedDialect == CifsMessageUtils.DIALECT_NTLANMAN))
{
session = new CifsServerPerSession(
connection,
smbHeader.Uid, //should be unique, windows always be zero
null,
DateTime.Now,
DateTime.Now,
string.Empty,
GenerateSessionGlobalId());
this.AddSession(session);
}
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = new CifsServerPerTreeConnect(
session,
CifsMessageUtils.ToSmbString(request.SmbData.Path, 0, false),
response.SmbParameters.TID,
this.GenerateTreeGlobalId(),
DateTime.Now);
this.AddTreeConnect(treeConnect);
}
}
#endregion
break;
case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
#region SMB_COM_TREE_CONNECT_ANDX
{
SmbTreeConnectAndxRequestPacket request = requestPacket as SmbTreeConnectAndxRequestPacket;
SmbTreeConnectAndxResponsePacket response = responsePacket as SmbTreeConnectAndxResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = new CifsServerPerTreeConnect(
session,
CifsMessageUtils.ToString(request.SmbData.Path, request.SmbHeader.Flags2),
smbHeader.Tid,
this.GenerateTreeGlobalId(),
DateTime.Now);
this.AddTreeConnect(treeConnect);
}
}
#endregion
break;
case SmbCommand.SMB_COM_TREE_DISCONNECT:
#region SMB_COM_TREE_DISCONNECT
{
SmbTreeDisconnectRequestPacket request = requestPacket as SmbTreeDisconnectRequestPacket;
SmbTreeDisconnectResponsePacket response = responsePacket as SmbTreeDisconnectResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
//If core protocol, no logoff any more, we have to remove the session if there is
// no treeconnects in it except this.
if (session.TreeConnectTable.Count == 1
&& (connection.SelectedDialect == CifsMessageUtils.DIALECT_PCNETWORK_PROGRAM
|| connection.SelectedDialect == CifsMessageUtils.DIALECT_NTLANMAN))
{
this.RemoveSession(session.SessionGlobalId);
}
else
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
this.RemoveTreeConnect(treeConnect.TreeGlobalId);
}
}
}
}
#endregion
break;
#endregion
#region Open File/Search
case SmbCommand.SMB_COM_OPEN:
#region SMB_COM_OPEN
{
SmbOpenRequestPacket request = requestPacket as SmbOpenRequestPacket;
SmbOpenResponsePacket response = responsePacket as SmbOpenResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
OplockLevelValue opLock = OplockLevelValue.None;
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
{
opLock = OplockLevelValue.Exclusive;
}
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
{
opLock = OplockLevelValue.Batch;
}
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
CifsMessageUtils.ToSmbString(request.SmbData.FileName, 0, false),
response.SmbParameters.FID,
response.SmbParameters.AccessMode,
opLock,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_CREATE:
#region SMB_COM_CREATE
{
SmbCreateRequestPacket request = requestPacket as SmbCreateRequestPacket;
SmbCreateResponsePacket response = responsePacket as SmbCreateResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
OplockLevelValue opLock = OplockLevelValue.None;
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
{
opLock = OplockLevelValue.Exclusive;
}
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
{
opLock = OplockLevelValue.Batch;
}
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
CifsMessageUtils.ToSmbString(request.SmbData.FileName, 0, false),
response.SmbParameters.FID,
(ushort)request.SmbParameters.FileAttributes,
opLock,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_CREATE_TEMPORARY:
#region SMB_COM_CREATE_TEMPORARY
{
SmbCreateTemporaryRequestPacket request = requestPacket as SmbCreateTemporaryRequestPacket;
SmbCreateTemporaryResponsePacket response = responsePacket as SmbCreateTemporaryResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
OplockLevelValue opLock = OplockLevelValue.None;
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
{
opLock = OplockLevelValue.Exclusive;
}
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
{
opLock = OplockLevelValue.Batch;
}
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
CifsMessageUtils.ToSmbString(response.SmbData.TemporaryFileName, 0, false),
response.SmbParameters.FID,
(uint)request.SmbParameters.FileAttributes,
opLock,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_CREATE_NEW:
#region SMB_COM_CREATE_NEW
{
SmbCreateNewRequestPacket request = requestPacket as SmbCreateNewRequestPacket;
SmbCreateNewResponsePacket response = responsePacket as SmbCreateNewResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
OplockLevelValue opLock = OplockLevelValue.None;
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
{
opLock = OplockLevelValue.Exclusive;
}
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
{
opLock |= OplockLevelValue.Batch;
}
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
CifsMessageUtils.ToSmbString(request.SmbData.FileName, 0, false),
response.SmbParameters.FID,
(uint)request.SmbParameters.FileAttributes,
opLock,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_OPEN_ANDX:
#region SMB_COM_OPEN_ANDX
{
SmbOpenAndxRequestPacket request = requestPacket as SmbOpenAndxRequestPacket;
SmbOpenAndxResponsePacket response = responsePacket as SmbOpenAndxResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
OplockLevelValue opLock = OplockLevelValue.None;
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPLOCK) == SmbFlags.SMB_FLAGS_OPLOCK)
{
opLock = OplockLevelValue.Exclusive;
}
if ((smbHeader.Flags & SmbFlags.SMB_FLAGS_OPBATCH) == SmbFlags.SMB_FLAGS_OPBATCH)
{
opLock |= OplockLevelValue.Batch;
}
string fileName;
if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE)
{
fileName = Encoding.Unicode.GetString(request.SmbData.FileName);
}
else
{
fileName = Encoding.ASCII.GetString(request.SmbData.FileName);
}
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
fileName,
response.SmbParameters.FID,
(uint)response.SmbParameters.FileAttrs,
opLock,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
//save FID for chained response like:
//treeConnect->openAndx->readAndx->close
//when "close", FID is need to close the open opened in openAndx.
if (response.AndxPacket != null)
{
//borrow smbHeader.Protocol to save FID for later process.
//smbHeader.Protocol also use a flag to differentiate a single packet from a
//batched andx packet.
//FID is ushort, impossible to impact smbHeader.Protocol's usage as
//a real packet header 0x424D53FF(0xFF, 'S', 'M', 'B')
SmbHeader andxHeader = response.AndxPacket.SmbHeader;
andxHeader.Protocol = response.SmbParameters.FID;
response.AndxPacket.SmbHeader = andxHeader;
}
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_NT_CREATE_ANDX:
#region SMB_COM_NT_CREATE_ANDX
{
SmbNtCreateAndxRequestPacket request = requestPacket as SmbNtCreateAndxRequestPacket;
SmbNtCreateAndxResponsePacket response = responsePacket as SmbNtCreateAndxResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
string fileName;
if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE)
{
fileName = Encoding.Unicode.GetString(request.SmbData.FileName);
}
else
{
fileName = Encoding.ASCII.GetString(request.SmbData.FileName);
}
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
fileName,
response.SmbParameters.FID,
(uint)response.SmbParameters.ExtFileAttributes,
response.SmbParameters.OplockLevel,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_OPEN_PRINT_FILE:
#region SMB_COM_OPEN_PRINT_FILE
{
SmbOpenPrintFileRequestPacket request = requestPacket as SmbOpenPrintFileRequestPacket;
SmbOpenPrintFileResponsePacket response = responsePacket as SmbOpenPrintFileResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
CifsMessageUtils.ToSmbString(request.SmbData.Identifier, 0, false),
response.SmbParameters.FID,
request.SmbParameters.Mode,
OplockLevelValue.None,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_TRANSACTION2:
#region Trans2Open2
{
SmbTrans2Open2RequestPacket request = requestPacket as SmbTrans2Open2RequestPacket;
SmbTrans2Open2FinalResponsePacket response = responsePacket as SmbTrans2Open2FinalResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
string fileName;
if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
SmbFlags2.SMB_FLAGS2_UNICODE)
{
fileName = Encoding.Unicode.GetString(request.Trans2Parameters.FileName);
}
else
{
fileName = Encoding.ASCII.GetString(request.Trans2Parameters.FileName);
}
CifsServerPerOpenFile open = new CifsServerPerOpenFile(
treeConnect,
fileName,
response.Trans2Parameters.Fid,
(uint)response.Trans2Parameters.FileAttributes,
OplockLevelValue.None,
this.GenerateFileGlobalId(),
request.SmbHeader.Pid);
this.AddOpenFile(open);
}
}
}
#endregion
#region Trans2FindFirst2
{
SmbTrans2FindFirst2RequestPacket request = requestPacket as SmbTrans2FindFirst2RequestPacket;
SmbTrans2FindFirst2FinalResponsePacket response = responsePacket as SmbTrans2FindFirst2FinalResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
string fileName;
if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
SmbFlags2.SMB_FLAGS2_UNICODE)
{
fileName = Encoding.Unicode.GetString(request.Trans2Parameters.FileName);
}
else
{
fileName = Encoding.ASCII.GetString(request.Trans2Parameters.FileName);
}
CifsServerPerOpenSearch openSearch = new CifsServerPerOpenSearch(
treeConnect,
response.Trans2Parameters.SID,
smbHeader.Mid,
smbHeader.Pid,
this.GenerateSearchGlobalId());
this.AddOpenSearch(openSearch);
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_WRITE_AND_CLOSE:
#region SMB_COM_WRITE_AND_CLOSE
{
SmbWriteAndCloseRequestPacket request = requestPacket as SmbWriteAndCloseRequestPacket;
SmbWriteAndCloseResponsePacket response = responsePacket as SmbWriteAndCloseResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
CifsServerPerOpenFile open = treeConnect.GetOpen(request.SmbParameters.FID);
if (open != null)
{
this.RemoveOpenFile(open.FileGlobalId);
}
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_CLOSE:
#region SMB_COM_CLOSE
{
SmbCloseRequestPacket request = requestPacket as SmbCloseRequestPacket;
SmbCloseResponsePacket response = responsePacket as SmbCloseResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
CifsServerPerOpenFile open = treeConnect.GetOpen(request.SmbParameters.FID);
if (open == null)
{
open = treeConnect.GetOpen((ushort)smbHeader.Protocol);
}
if (open != null)
{
this.RemoveOpenFile(open.FileGlobalId);
}
}
}
}
#endregion
break;
case SmbCommand.SMB_COM_FIND_CLOSE2:
#region SMB_COM_FIND_CLOSE2
{
SmbFindClose2RequestPacket request = requestPacket as SmbFindClose2RequestPacket;
SmbFindClose2ResponsePacket response = responsePacket as SmbFindClose2ResponsePacket;
CifsServerPerSession session = connection.GetSession(smbHeader.Uid);
if (request != null && response != null && session != null)
{
CifsServerPerTreeConnect treeConnect = session.GetTreeConnect(smbHeader.Tid);
if (treeConnect != null)
{
CifsServerPerOpenSearch openSearch = treeConnect.GetOpenSearch(
request.SmbParameters.SearchHandle); ;
if (openSearch != null)
{
this.RemoveOpenSearch(openSearch.SearchGlobalId);
}
}
}
}
#endregion
break;
#endregion
default:
// No Connection/Session/Tree/Open will be updated if other types of response.
break;
}
SmbBatchedRequestPacket batchedRequest = requestPacket as SmbBatchedRequestPacket;
SmbBatchedResponsePacket batchedResponse = responsePacket as SmbBatchedResponsePacket;
if (batchedRequest != null && batchedResponse != null)
{
//pass the FID stored in the andxHeader.Protocol into response.AndxPacket
if (batchedRequest.AndxPacket != null && batchedResponse.AndxPacket != null
&& batchedResponse.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET
&& batchedResponse.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER)
{
SmbHeader andxHeader = batchedResponse.AndxPacket.SmbHeader;
andxHeader.Protocol = smbHeader.Protocol;
batchedResponse.AndxPacket.SmbHeader = andxHeader;
}
this.UpdateResponseRoleContext(connection, batchedRequest.AndxPacket, batchedResponse.AndxPacket);
}
}