/// <summary> /// this function will be invoked every time a packet is sent or received. all logics about /// Client' states will be implemented here. /// </summary> /// <param name="connection">the connection object.</param> /// <param name="packet">the sent or received packet in stack transport.</param> protected override void UpdateRoleContext(CifsClientPerConnection connection, SmbPacket packet) { // Do nothing if no connection is found or the packet is not SmbPacket: if (connection == null || packet == null) { return; } // request packet: if (packet.PacketType == SmbPacketType.BatchedRequest || packet.PacketType == SmbPacketType.SingleRequest) { RequestPacketUpdateRoleContext(connection, packet, false); } // response packet: else if (packet.PacketType == SmbPacketType.BatchedResponse || packet.PacketType == SmbPacketType.SingleResponse) { if (!this.SmbUpdateContextWithResponsePacket(connection as SmbClientConnection, packet)) { SmbPacket request = this.GetOutstandingRequest(connection.ConnectionId, (ulong)packet.SmbHeader.Mid); ResponsePacketUpdateRoleContext(connection, request, packet); } ResponsePacketUpdateRoleContextRegular(connection, packet); } else { // Do nothing if neither request nor response. // No exception is thrown here because UpdateRoleContext is not responsible for checking the // invalidation of the packet. } }
protected virtual void ResponsePacketUpdateRoleContext( CifsClientPerConnection connection, SmbPacket request, SmbPacket response) { int connectionId = connection.ConnectionId; if (request ==null | response == null) { return; } #region To update Connection/Session/Tree/Open with response // Update context with success response: if (response.SmbHeader.Status == 0) { CifsClientPerSession session = new CifsClientPerSession(); CifsClientPerTreeConnect tree = new CifsClientPerTreeConnect(); CifsClientPerOpenFile openFile = new CifsClientPerOpenFile(); CifsClientPerOpenSearch openSearch = new CifsClientPerOpenSearch(); switch (response.SmbHeader.Command) { #region connection case SmbCommand.SMB_COM_NEGOTIATE: #region SMB_COM_NEGOTIATE SmbNegotiateRequestPacket negotiateRequest = request as SmbNegotiateRequestPacket; SmbNegotiateResponsePacket negotiateResponse = response as SmbNegotiateResponsePacket; if (negotiateRequest == null || negotiateResponse == null) { break; } // base class Connection: connection.NegotiateReceived = true; // common ADM: int dialectIndex = (int)(negotiateResponse.SmbParameters.DialectIndex); byte[] dialectBytes = negotiateRequest.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); // client ADM: connection.ShareLevelAccessControl = ((negotiateResponse.SmbParameters.SecurityMode & SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS) == SecurityModes.NONE); connection.ServerChallengeResponse = ((negotiateResponse.SmbParameters.SecurityMode & SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS) == SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS); if (connection.ServerChallengeResponse && ((negotiateResponse.SmbParameters.SecurityMode & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED) == SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) { connection.ServerSigningState = SignStateValue.ENABLED; } if (connection.ServerSigningState == SignStateValue.ENABLED && ((negotiateResponse.SmbParameters.SecurityMode & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) == SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)) { connection.ServerSigningState = SignStateValue.REQUIRED; } connection.ServerCapabilities = negotiateResponse.SmbParameters.Capabilities; connection.MaxBufferSize = negotiateResponse.SmbParameters.MaxBufferSize; // negotiate response: connection.SecurityMode = negotiateResponse.SmbParameters.SecurityMode; connection.MaxMpxCount = negotiateResponse.SmbParameters.MaxMpxCount; connection.MaxNumberVcs = negotiateResponse.SmbParameters.MaxNumberVcs; connection.MaxRawSize = negotiateResponse.SmbParameters.MaxRawSize; connection.SessionKey = negotiateResponse.SmbParameters.SessionKey; connection.SystemTime = negotiateResponse.SmbParameters.SystemTime.Time; connection.ServerTimeZone = negotiateResponse.SmbParameters.ServerTimeZone; if (negotiateResponse.SmbData.Challenge != null && negotiateResponse.SmbData.Challenge.Length >= 8) { connection.Challenge = BitConverter.ToUInt64(negotiateResponse.SmbData.Challenge, 0); } if (negotiateResponse.SmbData.DomainName != null) { connection.DomainName = new byte[negotiateResponse.SmbData.DomainName.Length]; Array.Copy(negotiateResponse.SmbData.DomainName, connection.DomainName, negotiateResponse.SmbData.DomainName.Length); } // stack sdk design: connection.ConnectionState = StackTransportState.ConnectionEstablished; // update: this.AddOrUpdateConnection(connection); #endregion break; #endregion #region session case SmbCommand.SMB_COM_SESSION_SETUP_ANDX: #region SMB_COM_SESSION_SETUP_ANDX SmbSessionSetupAndxRequestPacket sessionSetupRequest = request as SmbSessionSetupAndxRequestPacket; SmbSessionSetupAndxResponsePacket sessionSetupResponse = response as SmbSessionSetupAndxResponsePacket; if (sessionSetupRequest == null || sessionSetupResponse == null) { break; } session.ConnectionId = connectionId; session.SessionId = (ulong)sessionSetupResponse.SmbHeader.Uid; // in request: session.SessionKey = sessionSetupRequest.ImplicitNtlmSessionKey; session.MaxBufferSize = sessionSetupRequest.SmbParameters.MaxBufferSize; session.MaxMpxCount = sessionSetupRequest.SmbParameters.MaxMpxCount; session.VcNumber = sessionSetupRequest.SmbParameters.VcNumber; session.SessionKeyOfNegotiated = sessionSetupRequest.SmbParameters.SessionKey; session.Capabilities = sessionSetupRequest.SmbParameters.Capabilities; if ((sessionSetupRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE) { session.UserAccount = new CifsUserAccount( Encoding.Unicode.GetString(sessionSetupRequest.SmbData.PrimaryDomain), Encoding.Unicode.GetString(sessionSetupRequest.SmbData.AccountName), Encoding.Unicode.GetString(sessionSetupRequest.SmbData.OEMPassword)); session.ClientNativeOs = Encoding.Unicode.GetString(sessionSetupRequest.SmbData.NativeOS); session.ClientNativeLanMan = Encoding.Unicode.GetString(sessionSetupRequest.SmbData.NativeLanMan); } else { session.UserAccount = new CifsUserAccount( Encoding.ASCII.GetString(sessionSetupRequest.SmbData.PrimaryDomain), Encoding.ASCII.GetString(sessionSetupRequest.SmbData.AccountName), Encoding.ASCII.GetString(sessionSetupRequest.SmbData.OEMPassword)); session.ClientNativeOs = Encoding.ASCII.GetString(sessionSetupRequest.SmbData.NativeOS); session.ClientNativeLanMan = Encoding.ASCII.GetString(sessionSetupRequest.SmbData.NativeLanMan); } // in response: session.Action = sessionSetupResponse.SmbParameters.Action; if ((sessionSetupResponse.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE) { session.ServerNativeOs = Encoding.Unicode.GetString(sessionSetupResponse.SmbData.NativeOS); session.ServerNativeLanMan = Encoding.Unicode.GetString(sessionSetupResponse.SmbData.NativeLanMan); session.ServerPrimaryDomain = Encoding.Unicode.GetString(sessionSetupResponse.SmbData.PrimaryDomain); } else { session.ServerNativeOs = Encoding.ASCII.GetString(sessionSetupResponse.SmbData.NativeOS); session.ServerNativeLanMan = Encoding.ASCII.GetString(sessionSetupResponse.SmbData.NativeLanMan); session.ServerPrimaryDomain = Encoding.ASCII.GetString(sessionSetupResponse.SmbData.PrimaryDomain); } if (connection.ShareLevelAccessControl == false) { connection.IsSigningActive = true; connection.ConnectionSigningSessionKey = sessionSetupRequest.ImplicitNtlmSessionKey; connection.ConnectionSigningChallengeResponse = sessionSetupRequest.SmbData.UnicodePassword; AddOrUpdateConnection(connection); } // update: this.AddOrUpdateSession(session); #endregion break; case SmbCommand.SMB_COM_LOGOFF_ANDX: #region SMB_COM_LOGOFF_ANDX SmbLogoffAndxResponsePacket logoffResponse = response as SmbLogoffAndxResponsePacket; if (logoffResponse == null) { break; } this.RemoveSession(connectionId, (ulong)logoffResponse.SmbHeader.Uid); #endregion break; #endregion #region treeconnect case SmbCommand.SMB_COM_TREE_CONNECT: #region SMB_COM_TREE_CONNECT SmbTreeConnectRequestPacket treeConnectRequest = request as SmbTreeConnectRequestPacket; SmbTreeConnectResponsePacket treeConnectResponse = response as SmbTreeConnectResponsePacket; if (treeConnectRequest == null || treeConnectResponse == null) { break; } tree.ConnectionId = connectionId; tree.SessionId = (ulong)treeConnectResponse.SmbHeader.Uid; tree.TreeId = (ulong)treeConnectResponse.SmbHeader.Tid; tree.ShareName = CifsMessageUtils.ToSmbString(treeConnectRequest.SmbData.Path, 0, false); int index = tree.ShareName.LastIndexOf(@"\"); if (index > 0) { tree.Share = tree.ShareName.Substring(index + 1); } else { tree.Share = tree.ShareName; } this.AddOrUpdateTreeConnect(tree); #endregion break; case SmbCommand.SMB_COM_TREE_CONNECT_ANDX: #region SMB_COM_TREE_CONNECT_ANDX SmbTreeConnectAndxRequestPacket treeConnectAndxRequest = request as SmbTreeConnectAndxRequestPacket; SmbTreeConnectAndxResponsePacket treeConnectAndxResponse = response as SmbTreeConnectAndxResponsePacket; if (treeConnectAndxRequest == null || treeConnectAndxResponse == null) { break; } tree.ConnectionId = connectionId; tree.SessionId = (ulong)treeConnectAndxResponse.SmbHeader.Uid; tree.TreeId = (ulong)treeConnectAndxResponse.SmbHeader.Tid; if ((treeConnectAndxRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE) { tree.ShareName = Encoding.Unicode.GetString(treeConnectAndxRequest.SmbData.Path); } else { tree.ShareName = Encoding.ASCII.GetString(treeConnectAndxRequest.SmbData.Path); } int IndexOfShare = tree.ShareName.LastIndexOf(@"\"); if (IndexOfShare > 0) { tree.Share = tree.ShareName.Substring(IndexOfShare + 1); } else { tree.Share = tree.ShareName; } this.AddOrUpdateTreeConnect(tree); #endregion break; case SmbCommand.SMB_COM_TREE_DISCONNECT: #region SMB_COM_TREE_DISCONNECT SmbTreeDisconnectResponsePacket treeDisconnectResponse = response as SmbTreeDisconnectResponsePacket; if (treeDisconnectResponse == null) { break; } this.RemoveTreeConnect(connectionId, (ulong)treeDisconnectResponse.SmbHeader.Uid, (ulong)treeDisconnectResponse.SmbHeader.Tid); #endregion break; #endregion #region openfile case SmbCommand.SMB_COM_OPEN: #region SMB_COM_OPEN SmbOpenRequestPacket openRequest = request as SmbOpenRequestPacket; SmbOpenResponsePacket openResponse = response as SmbOpenResponsePacket; if (openRequest == null || openResponse == null) { break; } openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)openResponse.SmbHeader.Uid; openFile.TreeConnectId = (ulong)openResponse.SmbHeader.Tid; openFile.FileHandle = openResponse.SmbParameters.FID; openFile.FileName = CifsMessageUtils.ToSmbString(openRequest.SmbData.FileName, 0, false); this.AddOrUpdateOpenFile(openFile); #endregion break; case SmbCommand.SMB_COM_CREATE: #region SMB_COM_CREATE SmbCreateRequestPacket createRequest = request as SmbCreateRequestPacket; SmbCreateResponsePacket createResponse = response as SmbCreateResponsePacket; if (createRequest == null || createResponse == null) { break; } openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)createResponse.SmbHeader.Uid; openFile.TreeConnectId = (ulong)createResponse.SmbHeader.Tid; openFile.FileHandle = createResponse.SmbParameters.FID; openFile.FileName = CifsMessageUtils.ToSmbString(createRequest.SmbData.FileName, 0, false); this.AddOrUpdateOpenFile(openFile); #endregion break; case SmbCommand.SMB_COM_CREATE_TEMPORARY: #region SMB_COM_CREATE_TEMPORARY SmbCreateTemporaryRequestPacket createTemporaryRequest = request as SmbCreateTemporaryRequestPacket; SmbCreateTemporaryResponsePacket createTemporaryResponse = response as SmbCreateTemporaryResponsePacket; if (createTemporaryRequest == null || createTemporaryResponse == null) { break; } openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)createTemporaryResponse.SmbHeader.Uid; openFile.TreeConnectId = (ulong)createTemporaryResponse.SmbHeader.Tid; openFile.FileHandle = createTemporaryResponse.SmbParameters.FID; openFile.FileName = CifsMessageUtils.ToSmbString( createTemporaryResponse.SmbData.TemporaryFileName, 0, false); this.AddOrUpdateOpenFile(openFile); #endregion break; case SmbCommand.SMB_COM_CREATE_NEW: #region SMB_COM_CREATE_NEW SmbCreateNewRequestPacket createNewRequest = request as SmbCreateNewRequestPacket; SmbCreateNewResponsePacket createNewResponse = response as SmbCreateNewResponsePacket; if (createNewRequest == null || createNewResponse == null) { break; } openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)createNewResponse.SmbHeader.Uid; openFile.TreeConnectId = (ulong)createNewResponse.SmbHeader.Tid; openFile.FileHandle = createNewResponse.SmbParameters.FID; openFile.FileName = CifsMessageUtils.ToSmbString(createNewRequest.SmbData.FileName, 0, false); this.AddOrUpdateOpenFile(openFile); #endregion break; case SmbCommand.SMB_COM_OPEN_ANDX: #region SMB_COM_OPEN_ANDX SmbOpenAndxRequestPacket openAndxRequest = request as SmbOpenAndxRequestPacket; SmbOpenAndxResponsePacket openAndxResponse = response as SmbOpenAndxResponsePacket; if (openAndxRequest == null || openAndxResponse == null) { break; } openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)openAndxResponse.SmbHeader.Uid; openFile.TreeConnectId = (ulong)openAndxResponse.SmbHeader.Tid; openFile.FileHandle = openAndxResponse.SmbParameters.FID; if ((openAndxRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE) { openFile.FileName = Encoding.Unicode.GetString(openAndxRequest.SmbData.FileName); } else { openFile.FileName = Encoding.ASCII.GetString(openAndxRequest.SmbData.FileName); } this.AddOrUpdateOpenFile(openFile); #endregion //save FID for chained response like: //treeConnect->openAndx->readAndx->close //when "close", FID is need to close the open opened in openAndx. if (openAndxResponse.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 = openAndxResponse.AndxPacket.SmbHeader; andxHeader.Protocol = openAndxResponse.SmbParameters.FID; openAndxResponse.AndxPacket.SmbHeader = andxHeader; } break; case SmbCommand.SMB_COM_NT_CREATE_ANDX: #region SMB_COM_NT_CREATE_ANDX SmbNtCreateAndxRequestPacket ntCreateAndxRequest = request as SmbNtCreateAndxRequestPacket; SmbNtCreateAndxResponsePacket ntCreateAndxResponse = response as SmbNtCreateAndxResponsePacket; if (ntCreateAndxRequest == null || ntCreateAndxResponse == null) { break; } openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)ntCreateAndxResponse.SmbHeader.Uid; openFile.TreeConnectId = (ulong)ntCreateAndxResponse.SmbHeader.Tid; openFile.FileHandle = ntCreateAndxResponse.SmbParameters.FID; if ((ntCreateAndxRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE) { openFile.FileName = Encoding.Unicode.GetString(ntCreateAndxRequest.SmbData.FileName); } else { openFile.FileName = Encoding.ASCII.GetString(ntCreateAndxRequest.SmbData.FileName); } this.AddOrUpdateOpenFile(openFile); #endregion break; case SmbCommand.SMB_COM_OPEN_PRINT_FILE: #region SMB_COM_OPEN_PRINT_FILE SmbOpenPrintFileRequestPacket openPrintFileRequest = request as SmbOpenPrintFileRequestPacket; SmbOpenPrintFileResponsePacket openPrintFileResponse = response as SmbOpenPrintFileResponsePacket; if (openPrintFileRequest == null || openPrintFileResponse == null) { break; } openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)openPrintFileResponse.SmbHeader.Uid; openFile.TreeConnectId = (ulong)openPrintFileResponse.SmbHeader.Tid; openFile.FileHandle = openPrintFileResponse.SmbParameters.FID; openFile.FileName = CifsMessageUtils.ToSmbString( openPrintFileRequest.SmbData.Identifier, 0, false); this.AddOrUpdateOpenFile(openFile); #endregion break; case SmbCommand.SMB_COM_TRANSACTION2: #region Trans2Open2 SmbTrans2Open2RequestPacket trans2Open2Request = request as SmbTrans2Open2RequestPacket; SmbTrans2Open2FinalResponsePacket trans2Open2Response = response as SmbTrans2Open2FinalResponsePacket; if (trans2Open2Request != null && trans2Open2Response != null) { openFile.ConnectionId = connectionId; openFile.SessionId = (ulong)trans2Open2Response.SmbHeader.Uid; openFile.TreeConnectId = (ulong)trans2Open2Response.SmbHeader.Tid; openFile.FileHandle = trans2Open2Response.Trans2Parameters.Fid; if ((trans2Open2Request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE) { openFile.FileName = Encoding.Unicode.GetString( trans2Open2Request.Trans2Parameters.FileName); } else { openFile.FileName = Encoding.ASCII.GetString( trans2Open2Request.Trans2Parameters.FileName); } this.AddOrUpdateOpenFile(openFile); break; } #endregion #region Trans2FindFirst2 SmbTrans2FindFirst2RequestPacket trans2FindFirst2Request = request as SmbTrans2FindFirst2RequestPacket; SmbTrans2FindFirst2FinalResponsePacket trans2FindFirst2Response = response as SmbTrans2FindFirst2FinalResponsePacket; if (trans2FindFirst2Request != null && trans2FindFirst2Response != null) { openSearch.ConnectionId = connectionId; openSearch.SessionId = (ulong)trans2FindFirst2Response.SmbHeader.Uid; openSearch.TreeConnectId = (ulong)trans2FindFirst2Response.SmbHeader.Tid; openSearch.SearchID = trans2FindFirst2Response.Trans2Parameters.SID; if ((trans2FindFirst2Request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE) { openSearch.SearchName = Encoding.Unicode.GetString( trans2FindFirst2Request.Trans2Parameters.FileName); } else { openSearch.SearchName = Encoding.ASCII.GetString( trans2FindFirst2Request.Trans2Parameters.FileName); } this.AddOrUpdateOpenSearch(openSearch); break; } #endregion break; case SmbCommand.SMB_COM_WRITE_AND_CLOSE: #region SMB_COM_WRITE_AND_CLOSE SmbWriteAndCloseRequestPacket writeAndCloseRequest = request as SmbWriteAndCloseRequestPacket; if (writeAndCloseRequest == null) { break; } this.RemoveOpenFile(connectionId, (ulong)response.SmbHeader.Uid, (ulong)response.SmbHeader.Tid, writeAndCloseRequest.SmbParameters.FID); #endregion break; case SmbCommand.SMB_COM_CLOSE: #region SMB_COM_CLOSE // Get FID from CLOSE request. // If fail, then get FID from the Batched Request. // If still fail, then Get FID from the Batched Response. ushort closeFId = 0; SmbCloseRequestPacket closeRequest = request as SmbCloseRequestPacket; if (closeRequest != null) { //Neither SMB_PROTOCOL_IDENTIFIER, or SMB_PROTOCOL_ANDXPACKET, then must be a FID if (response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER && response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET) { closeFId = (ushort)response.SmbHeader.Protocol; } else { closeFId = closeRequest.SmbParameters.FID; } this.RemoveOpenFile(connectionId, (ulong)response.SmbHeader.Uid, (ulong)response.SmbHeader.Tid, closeFId); } #endregion break; #endregion #region opensearch case SmbCommand.SMB_COM_FIND_CLOSE2: #region SMB_COM_FIND_CLOSE2 SmbFindClose2RequestPacket findClose2Request = request as SmbFindClose2RequestPacket; if (findClose2Request == null) { break; } this.RemoveOpenSearch(connectionId, (ulong)response.SmbHeader.Uid, (ulong)response.SmbHeader.Tid, findClose2Request.SmbParameters.SearchHandle); #endregion break; #endregion default: // No Connection/Session/Tree/Open will be updated if other types of response. break; } SmbBatchedRequestPacket smbBatchedRequest = request as SmbBatchedRequestPacket; SmbBatchedResponsePacket smbBatchedResponse = response as SmbBatchedResponsePacket; if (smbBatchedRequest != null && smbBatchedResponse != null) { //pass the FID stored in the andxHeader.Protocol into response.AndxPacket if (smbBatchedRequest.AndxPacket != null && smbBatchedResponse.AndxPacket != null && response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET && response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER) { SmbHeader andxHeader = smbBatchedResponse.AndxPacket.SmbHeader; andxHeader.Protocol = smbBatchedResponse.SmbHeader.Protocol; smbBatchedResponse.AndxPacket.SmbHeader = andxHeader; } this.ResponsePacketUpdateRoleContext(connection, smbBatchedRequest.AndxPacket, smbBatchedResponse.AndxPacket); } } #endregion }
protected virtual void UpdateRoleContext(CifsClientPerConnection connection, SmbPacket packet) { // request packet: if ((packet.PacketType == SmbPacketType.BatchedRequest || packet.PacketType == SmbPacketType.SingleRequest) // Skip over the OpLock Break Notification request sent from server. && packet.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER_ASYNC && packet.SmbHeader.Mid != CifsMessageUtils.INVALID_MID) { RequestPacketUpdateRoleContext(connection, packet, false); } // response packet: else if (packet.PacketType == SmbPacketType.BatchedResponse || packet.PacketType == SmbPacketType.SingleResponse) { SmbPacket request = this.GetOutstandingRequest(connection.ConnectionId, (ulong)packet.SmbHeader.Mid); ResponsePacketUpdateRoleContext(connection, request, packet); if (connection.IsSigningActive && packet.IsSignRequired) { packet.IsSignatureCorrect = CifsMessageUtils.VerifySignature( packet, connection.ConnectionSigningSessionKey, (uint)connection.ClientResponseSequenceNumberList[packet.SmbHeader.Mid], connection.ConnectionSigningChallengeResponse); } ResponsePacketUpdateRoleContextRegular(connection, packet); } else { // Do nothing if neither request nor response. // No exception is thrown here because UpdateRoleContext is not responsible for checking the // invalidation of the packet. } }
/// <summary> /// this function will be invoked every time a packet is sent or received. all logics about /// Client' states will be implemented here. /// request packet update the context /// </summary> /// <param name="connection">the connection object.</param> /// <param name="packet">the sent or received packet in stack transport.</param> /// <param name="isAndxPacket">the packet is andx packet or not.</param> protected virtual void RequestPacketUpdateRoleContext(CifsClientPerConnection connection, SmbPacket packet, bool isAndxPacket) { int connectionId = connection.ConnectionId; if (packet == null) { return; } #region To update Connection/Session/Tree/Open with request switch (packet.SmbHeader.Command) { case SmbCommand.SMB_COM_NEGOTIATE: connection.NegotiateSent = true; this.AddOrUpdateConnection(connection); break; default: // No Connection/Session/Tree/Open will be updated for other requests. break; } #endregion #region AddOutstandingRequest if (!isAndxPacket && packet.SmbHeader.Command != SmbCommand.SMB_COM_TRANSACTION_SECONDARY && packet.SmbHeader.Command != SmbCommand.SMB_COM_TRANSACTION2_SECONDARY && packet.SmbHeader.Command != SmbCommand.SMB_COM_NT_TRANSACT_SECONDARY && packet.SmbHeader.Command != SmbCommand.SMB_COM_NT_CANCEL) { this.AddOutstandingRequest(connectionId, packet); } else { // do nothing for requests of Andx, SECONDARY and CANCEL. } #endregion #region UpdateSequenceNumber if (!isAndxPacket) { this.UpdateSequenceNumber(connectionId, packet); } SmbBatchedRequestPacket batchedPacket = packet as SmbBatchedRequestPacket; if (batchedPacket != null) { RequestPacketUpdateRoleContext(connection, batchedPacket.AndxPacket, true); } #endregion }
/// <summary> /// if the connection identified by connectionId has been existed in connectionList, /// this connection will be updated into the connectionList. otherwise, this connection /// will be added into the connectionList. /// </summary> /// <param name="connection">the connection to be added or updated.</param> public void AddOrUpdateConnection(CifsClientPerConnection connection) { if (connection == null) { return; } lock (this.contextCollection) { for (int i = this.contextCollection.ConnectionList.Count - 1; i >= 0; i--) { if (this.contextCollection.ConnectionList[i].ConnectionId == connection.ConnectionId) { // update the connection: this.contextCollection.ConnectionList[i] = connection; return; } } // add the connection: connection.GlobalIndex = this.contextCollection.NextConnectionGlobalIndex; this.contextCollection.ConnectionList.Add(connection); this.contextCollection.NextConnectionGlobalIndex += 1; } }
/// <summary> /// Deep copy constructor. /// if need to copy the connection instance, you must call the Clone method. /// its sub class inherit from this, and need to provide more features. /// </summary> public CifsClientPerConnection(CifsClientPerConnection connection) : base(connection) { lock (connection) { // common ADM: this.SelectedDialect = connection.SelectedDialect; this.IsSigningActive = connection.IsSigningActive; if (connection.ConnectionSigningSessionKey != null) { this.ConnectionSigningSessionKey = new byte[connection.ConnectionSigningSessionKey.Length]; Array.Copy(connection.ConnectionSigningSessionKey, this.ConnectionSigningSessionKey, connection.ConnectionSigningSessionKey.Length); } if (connection.ConnectionSigningChallengeResponse != null) { this.ConnectionSigningChallengeResponse = new byte[ connection.ConnectionSigningChallengeResponse.Length]; Array.Copy(connection.ConnectionSigningChallengeResponse, this.ConnectionSigningChallengeResponse, connection.ConnectionSigningChallengeResponse.Length); } // client ADM: this.ShareLevelAccessControl = connection.ShareLevelAccessControl; this.ServerChallengeResponse = connection.ServerChallengeResponse; this.ServerSigningState = connection.ServerSigningState; this.ClientNextSendSequenceNumber = connection.ClientNextSendSequenceNumber; if (connection.ClientResponseSequenceNumberList != null) { this.ClientResponseSequenceNumberList = new Dictionary<ushort, ulong>(); foreach (KeyValuePair<ushort, ulong> obj in connection.ClientResponseSequenceNumberList) { this.ClientResponseSequenceNumberList.Add(obj.Key, obj.Value); } } if (connection.NTLMEncryptionKey != null) { this.NTLMEncryptionKey = new byte[connection.NTLMEncryptionKey.Length]; Array.Copy(connection.NTLMEncryptionKey, this.NTLMEncryptionKey, connection.NTLMEncryptionKey.Length); } this.ServerCapabilities = connection.ServerCapabilities; this.NegotiateSent = connection.NegotiateSent; this.MaxBufferSize = connection.MaxBufferSize; this.SessionID = connection.SessionID; if (connection.OpLockTable != null) { this.OpLockTable = new Dictionary<ushort, byte>(); foreach (KeyValuePair<ushort, byte> obj in connection.OpLockTable) { this.OpLockTable.Add(obj.Key, obj.Value); } } // negotiate response: this.SecurityMode = connection.SecurityMode; this.MaxMpxCount = connection.MaxMpxCount; this.MaxNumberVcs = connection.MaxNumberVcs; this.MaxRawSize = connection.MaxRawSize; this.SessionKey = connection.SessionKey; this.SystemTime = connection.SystemTime; this.ServerTimeZone = connection.ServerTimeZone; this.Challenge = connection.Challenge; if (connection.DomainName != null) { this.DomainName = new byte[connection.DomainName.Length]; Array.Copy(connection.DomainName, this.DomainName, connection.DomainName.Length); } // stack sdk design: this.ServerNetbiosName = string.Empty; this.ClientNetbiosName = string.Empty; this.ConnectionState = StackTransportState.Init; this.pendingResponseList = new Dictionary<ulong, SmbPacket>(); this.SessionTable = new Collection<Session>(); this.nextMessageId = 1; // stack sdk design: this.ServerNetbiosName = connection.ServerNetbiosName; this.ClientNetbiosName = connection.ClientNetbiosName; this.ConnectionState = connection.ConnectionState; if (connection.pendingResponseList != null) { this.pendingResponseList = new Dictionary<ulong, SmbPacket>(); foreach (KeyValuePair<ulong, SmbPacket> pair in connection.pendingResponseList) { this.pendingResponseList.Add(pair.Key, pair.Value.Clone() as SmbPacket); } } if (connection.sessionTable != null) { this.sessionTable = new Collection<Session>(); foreach (CifsClientPerSession session in connection.sessionTable) { this.sessionTable.Add(session.Clone()); } } this.nextMessageId = connection.nextMessageId; } }
/// <summary> /// to set up Netbios session with server, and add the connection into context. /// </summary> /// <param name="server">the server NetBios Name.</param> /// <param name="client">the local NetBios Name.</param> /// <returns>the Identity of the connection. if connected, is the session number /// of the Netbios session; otherwise -1.</returns> /// <exception cref="System.ArgumentNullException">the server and client must not be null.</exception> /// <exception cref="System.InvalidOperationException"> failed to connect for Netbios error. </exception> public int Connect(string server, string client) { if (server == null) { throw new ArgumentNullException("server"); } if (client == null) { throw new ArgumentNullException("client"); } NetbiosTransportConfig transportConfig = new NetbiosTransportConfig(); transportConfig.Type = StackTransportType.Netbios; transportConfig.Role = Role.Client; transportConfig.BufferSize = this.ptfConfig.NcbBufferSize; transportConfig.MaxSessions = this.ptfConfig.NcbMaxSessions; transportConfig.MaxNames = this.ptfConfig.NcbMaxNames; transportConfig.RemoteNetbiosName = server; transportConfig.LocalNetbiosName = client; this.transport = new TransportStack(transportConfig, this.decoder.DecodePacket); this.connectionId = (int)this.transport.Connect(); CifsClientPerConnection connection = new CifsClientPerConnection(); connection.ConnectionId = this.connectionId; connection.ConnectionState = StackTransportState.ConnectionEstablished; connection.ServerNetbiosName = server; connection.ClientNetbiosName = client; this.context.AddOrUpdateConnection(connection); return this.connectionId; }
/// <summary> /// Deep copy constructor. /// if need to copy the connection instance, you must call the Clone method. /// its sub class inherit from this, and need to provide more features. /// </summary> public CifsClientPerConnection(CifsClientPerConnection connection) : base(connection) { lock (connection) { // common ADM: this.SelectedDialect = connection.SelectedDialect; this.IsSigningActive = connection.IsSigningActive; if (connection.ConnectionSigningSessionKey != null) { this.ConnectionSigningSessionKey = new byte[connection.ConnectionSigningSessionKey.Length]; Array.Copy(connection.ConnectionSigningSessionKey, this.ConnectionSigningSessionKey, connection.ConnectionSigningSessionKey.Length); } if (connection.ConnectionSigningChallengeResponse != null) { this.ConnectionSigningChallengeResponse = new byte[ connection.ConnectionSigningChallengeResponse.Length]; Array.Copy(connection.ConnectionSigningChallengeResponse, this.ConnectionSigningChallengeResponse, connection.ConnectionSigningChallengeResponse.Length); } // client ADM: this.ShareLevelAccessControl = connection.ShareLevelAccessControl; this.ServerChallengeResponse = connection.ServerChallengeResponse; this.ServerSigningState = connection.ServerSigningState; this.ClientNextSendSequenceNumber = connection.ClientNextSendSequenceNumber; if (connection.ClientResponseSequenceNumberList != null) { this.ClientResponseSequenceNumberList = new Dictionary <ushort, ulong>(); foreach (KeyValuePair <ushort, ulong> obj in connection.ClientResponseSequenceNumberList) { this.ClientResponseSequenceNumberList.Add(obj.Key, obj.Value); } } if (connection.NTLMEncryptionKey != null) { this.NTLMEncryptionKey = new byte[connection.NTLMEncryptionKey.Length]; Array.Copy(connection.NTLMEncryptionKey, this.NTLMEncryptionKey, connection.NTLMEncryptionKey.Length); } this.ServerCapabilities = connection.ServerCapabilities; this.NegotiateSent = connection.NegotiateSent; this.MaxBufferSize = connection.MaxBufferSize; this.SessionID = connection.SessionID; if (connection.OpLockTable != null) { this.OpLockTable = new Dictionary <ushort, byte>(); foreach (KeyValuePair <ushort, byte> obj in connection.OpLockTable) { this.OpLockTable.Add(obj.Key, obj.Value); } } // negotiate response: this.SecurityMode = connection.SecurityMode; this.MaxMpxCount = connection.MaxMpxCount; this.MaxNumberVcs = connection.MaxNumberVcs; this.MaxRawSize = connection.MaxRawSize; this.SessionKey = connection.SessionKey; this.SystemTime = connection.SystemTime; this.ServerTimeZone = connection.ServerTimeZone; this.Challenge = connection.Challenge; if (connection.DomainName != null) { this.DomainName = new byte[connection.DomainName.Length]; Array.Copy(connection.DomainName, this.DomainName, connection.DomainName.Length); } // stack sdk design: this.ServerNetbiosName = string.Empty; this.ClientNetbiosName = string.Empty; this.ConnectionState = StackTransportState.Init; this.pendingResponseList = new Dictionary <ulong, SmbPacket>(); this.SessionTable = new Collection <Session>(); this.nextMessageId = 1; // stack sdk design: this.ServerNetbiosName = connection.ServerNetbiosName; this.ClientNetbiosName = connection.ClientNetbiosName; this.ConnectionState = connection.ConnectionState; if (connection.pendingResponseList != null) { this.pendingResponseList = new Dictionary <ulong, SmbPacket>(); foreach (KeyValuePair <ulong, SmbPacket> pair in connection.pendingResponseList) { this.pendingResponseList.Add(pair.Key, pair.Value.Clone() as SmbPacket); } } if (connection.sessionTable != null) { this.sessionTable = new Collection <Session>(); foreach (CifsClientPerSession session in connection.sessionTable) { this.sessionTable.Add(session.Clone()); } } this.nextMessageId = connection.nextMessageId; } }