/// <summary> /// Add an open into the GlobalOpenTable, and to its own TreeConnect's OpenTable. /// </summary> /// <param name="open">The open to be added or updated.</param> /// <exception cref="System.ArgumentNullException">The open or open.TreeConnectis null</exception> /// <exception cref="System.ArgumentException">The open already exists</exception> public void AddOpenFile(CifsServerPerOpenFile open) { if (open == null || open.TreeConnect == null) { throw new ArgumentException("The open or open.TreeConnect is null."); } lock (this.globalTables) { (open.TreeConnect as CifsServerPerTreeConnect).AddOpen(open); this.globalTables.GlobalOpenTable.Add(open.FileGlobalId, open); } }
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); } }
public SmbLockingAndxRequestPacket CreateLockingAndxRequest( CifsServerPerOpenFile open, NewOplockLevelValue newOplockLevel) { SmbLockingAndxRequestPacket request = new SmbLockingAndxRequestPacket(); SmbHeader smbHeader = new SmbHeader(); smbHeader.Protocol = CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER; smbHeader.Command = SmbCommand.SMB_COM_LOCKING_ANDX; smbHeader.Uid = (ushort)open.Session.SessionId; smbHeader.Tid = (ushort)open.TreeConnect.TreeConnectId; smbHeader.Mid = CifsMessageUtils.INVALID_MID; request.SmbHeader = smbHeader; SMB_COM_LOCKING_ANDX_Request_SMB_Parameters smbParameters = request.SmbParameters; smbParameters.FID = (ushort)open.FileId; smbParameters.NewOplockLevel = newOplockLevel; smbParameters.TypeOfLock = LockingAndxTypeOfLock.OPLOCK_RELEASE; smbParameters.WordCount = (byte)(TypeMarshal.GetBlockMemorySize(smbParameters) / 2); request.SmbParameters = smbParameters; request.AndxPacket = null; return request; }