diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/SIPSec/IpSecPlugin/src/CSipSecAgreeContext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realtimenetprots/sipfw/SIP/SIPSec/IpSecPlugin/src/CSipSecAgreeContext.cpp Tue Feb 02 01:03:15 2010 +0200 @@ -0,0 +1,589 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Name : CSipSecAgreeContext.cpp +// Part of : SIPSec +// Version : SIP/5.0 +// + + + +#include "sipstrings.h" +#include "siprequest.h" +#include "sipresponse.h" +#include "sipcseqheader.h" +#include "MSIPTransportMgr.h" +#include "MIpSecMechanismParams.h" +#include "MSIPSecSecurityMechanismObserver.h" +#include "CSipSecAgreeRecord.h" +#include "CSipSecAgreeContext.h" +#include "SipSecUtils.h" + +#ifdef CPPUNIT_TEST +#include "CActiveObjController1.h" +#endif + + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::NewL +// ---------------------------------------------------------------------------- +// +CSipSecAgreeContext* CSipSecAgreeContext::NewL( + MIpSecMechanismParams& aParams, + TSIPTransportParams& aTransportParams, + CSIPResponse& aResponse, + CSIPRequest& aRequest, + TInetAddr& aRemoteAddress, + MSIPSecUser* aUser, + MSIPSecSecurityMechanismObserver& aObserver, + RPointerArray& aStates ) + { + CSipSecAgreeContext* + self = CSipSecAgreeContext::NewLC( aParams, + aTransportParams, + aResponse, + aRequest, + aRemoteAddress, + aUser, + aObserver, + aStates ); + CleanupStack::Pop( self ); + return self; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::NewLC +// ---------------------------------------------------------------------------- +// +CSipSecAgreeContext* CSipSecAgreeContext::NewLC( + MIpSecMechanismParams& aParams, + TSIPTransportParams& aTransportParams, + CSIPResponse& aResponse, + CSIPRequest& aRequest, + TInetAddr& aRemoteAddress, + MSIPSecUser* aUser, + MSIPSecSecurityMechanismObserver& aObserver, + RPointerArray& aStates ) + { + CSipSecAgreeContext* self = + new ( ELeave ) CSipSecAgreeContext( aParams, aObserver, aStates ); + CleanupStack::PushL(self); + self->ConstructL( aTransportParams, + aResponse, + aRequest, + aRemoteAddress, + aUser ); + return self; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::CSipSecAgreeContext +// ---------------------------------------------------------------------------- +// +CSipSecAgreeContext::CSipSecAgreeContext( + MIpSecMechanismParams& aParams, + MSIPSecSecurityMechanismObserver& aObserver, + RPointerArray& aStates ) : + iParams( aParams ), + iObserver( &aObserver ), + iStates( aStates ) +#ifdef CPPUNIT_TEST + , iSecAgreeRecords( 1 ) +#endif + { + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::ConstructL +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::ConstructL( TSIPTransportParams& aTransportParams, + CSIPResponse& aResponse, + CSIPRequest& aRequest, + TInetAddr& aRemoteAddress, + MSIPSecUser* aUser ) + { + User::LeaveIfError( iParams.TransportMan().GetLocalAddress( + aTransportParams.IapId(), + iLocalAddress ) ); + iRemoteAddress = aRemoteAddress; + iSecUser = aUser; + + CSipSecAgreeRecord* r = + CSipSecAgreeRecord::NewLC( iStates, *this, aTransportParams ); + +#ifdef CPPUNIT_TEST + iObjCtr = new ( ELeave ) CActiveObjController1(); + iObjCtr->iContext = this; + iObjCtr->iRcrdCtrl1 = r->iObjCtr; + r->iObjCtr->iFeedBack = iObjCtr; +#endif + + r->Resp4xxL( aResponse, aRequest ); + iSecAgreeRecords.AppendL( r ); + CleanupStack::Pop( r ); + } + +// ---------------------------------------------------------------------------- +// Destructor +// ---------------------------------------------------------------------------- +// +CSipSecAgreeContext::~CSipSecAgreeContext() + { + iSecAgreeRecords.ResetAndDestroy(); + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::MechParams +// ---------------------------------------------------------------------------- +// +MIpSecMechanismParams& CSipSecAgreeContext::MechParams() + { + return iParams; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::LocalAddress +// ---------------------------------------------------------------------------- +// +TInetAddr CSipSecAgreeContext::LocalAddress() + { + return iLocalAddress; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::PolicyServer +// ---------------------------------------------------------------------------- +// +RIpsecPolicyServ& CSipSecAgreeContext::PolicyServer() + { + return iParams.PolicyServer(); + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::RemoteAddress +// ---------------------------------------------------------------------------- +// +TInetAddr CSipSecAgreeContext::RemoteAddress() + { + return iRemoteAddress; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::HasOnlyOneRecord +// ---------------------------------------------------------------------------- +// +TBool CSipSecAgreeContext::HasOnlyOneRecord() const + { + TInt pos( 0 ); + return ( NextRecord( pos ) != NULL && !NextRecord( pos ) ); + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::HasRecordInState +// ---------------------------------------------------------------------------- +// +TBool +CSipSecAgreeContext::HasRecordInState( CState::TSecAgreeRecordState aState ) + { + TInt pos( 0 ); + TBool found( EFalse ); + CSipSecAgreeRecord* record = NextRecord( pos ); + for ( ; !found && record; record = NextRecord( pos ) ) + { + found = ( record->State() == aState ); + } + return found; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::SaDeleted +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::SaDeleted( CSipSecAgreeRecord* aRecord ) + { + DeleteRecord( aRecord ); + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::SaCleared +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::SaCleared( CSipSecAgreeRecord* aRecord ) + { + DeleteRecord( aRecord ); + if ( iSecAgreeRecords.Count() == 0 ) + { + iParams.ContextCleared( this ); + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::SAReady +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::SAReady( TBool aSuccess ) + { + if ( iObserver ) + { + iObserver->SAReady( aSuccess ); + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::HasLongerLifetimeSA +// ---------------------------------------------------------------------------- +// +TBool +CSipSecAgreeContext::HasLongerLifetimeSA( TUint aTimeToCompareInMillisecs, + TUint& aLongerLifetimeInMillisecs ) + { + // Compare only with "inuse" records + TBool found( EFalse ); + TInt pos( 0 ); + for ( CSipSecAgreeRecord* record = NextRecord( pos ); + !found && record; + record = NextRecord( pos ) ) + { + TUint expiresAfter = record->ExpiresAfter(); + + if ( record->State() == CState::EInUse && + ( expiresAfter > aTimeToCompareInMillisecs ) ) + { + aLongerLifetimeInMillisecs = expiresAfter; + found = ETrue; + } + } + return found; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::HasSecUser +// ---------------------------------------------------------------------------- +// +TBool CSipSecAgreeContext::HasSecUser( const MSIPSecUser* aSecUser ) const + { + return aSecUser == iSecUser; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::HasNextHop +// Ignore context for which clearing has started. +// ---------------------------------------------------------------------------- +// +TBool CSipSecAgreeContext::HasNextHop( const TInetAddr& aNextHop ) const + { + return ( !aNextHop.IsWildAddr() && + iRemoteAddress.Match( aNextHop ) && + !iClearOrdered ); + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::ApplyRulesL +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::ApplyRulesL( TSIPTransportParams& aTransportParams, + CSIPRequest& aRequest, + const TDesC8& aOutboundProxy, + MSIPSecUser* aUser ) + { + TInt pos( 0 ); + CSipSecAgreeRecord* record = NextRecord( pos ); + + if ( SipSecUtils::Match( SipStrConsts::ERegister, aRequest.Method() ) ) + { + // Other MSIPSecUsers cannot use existing context (SA) + // for registration to the same outbound proxy. + __ASSERT_ALWAYS( HasSecUser( aUser ), User::Leave( KErrInUse ) ); + + for ( ; record; record = NextRecord( pos ) ) + { + record->RegisterL( aTransportParams, aRequest, aOutboundProxy ); + } + } + else + { + for ( ; record; record = NextRecord( pos ) ) + { + record->ReguestL( aTransportParams, aRequest, aOutboundProxy ); + } + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::ApplyRulesL +// IPSec is only interested on 401 and 200 responses +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::ApplyRulesL( + CSIPResponse& aResponse, + CSIPRequest& aRequest, + MSIPSecSecurityMechanismObserver& aObserver ) + { + if ( aResponse.ResponseCode() == K401Response ) + { + // First check if a new record must be created + CreateNewSecAgreeRecordIfNeededL(); + + TInt pos( 0 ); + for ( CSipSecAgreeRecord* record = NextRecord( pos ); + record; + record = NextRecord( pos ) ) + { + record->Resp4xxL( aResponse, aRequest ); + } + iObserver = &aObserver; + } + if ( aResponse.ResponseCode() == K200Response ) + { + CSIPCSeqHeader* h = static_cast( + SipSecUtils::SingleHeader( aResponse, SipStrConsts::ECSeqHeader ) ); + if ( h && h->Method() == _STRINGF( SipStrConsts::ERegister ) ) + { + TInt pos( 0 ); + for ( CSipSecAgreeRecord* record = NextRecord( pos ); + record; + record = NextRecord( pos ) ) + { + record->Resp2xxL( aResponse ); + } + iObserver = &aObserver; + } + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::CreateNewSecAgreeRecordIfNeededL +// Create new record if an existing record is in InUse, Deleting or Clearing +// state. Deleting and Clearing states are included because in some very rare +// scenario 4xx might be received before SA deletion is completed, and such +// situation must not cause malfunction. +// +// +// If two records exist already. Drop one of them by setting it obsolete. +// +// Selecting the record to be obsoleted: +// SA-1's state SA-2's state drop +// ------------ ------------ ---- +// InUse Tentative..PendingPolicy SA-2 +// Old..Deleting InUse SA-1 +// +// When 2xx is received, SA-1 enters "Old" and SA-2 enters "InUse", +// so two records can't be in "InUse". +// +// +// New record uses initially same transport params, as it must share protected +// server port with old record. When new record is reserving transport, +// transport params will be updated. New record derives Security-Client and +// Security-Verify headers from response and corresponding request. +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::CreateNewSecAgreeRecordIfNeededL() + { + if ( HasRecordInState( CState::EInUse ) || + HasRecordInState( CState::EDeleting ) || + HasRecordInState( CState::EClearing ) ) + { + if ( !HasOnlyOneRecord() ) + { + TInt pos( 0 ); + CSipSecAgreeRecord* rec = NextRecord( pos ); + if(rec) + { + if ( rec->State() == CState::EInUse ) + { + // Record is "in use", drop the other record + rec = NextRecord( pos ); + if(rec) + { + __ASSERT_ALWAYS( rec->State() != CState::EInUse, + User::Leave( KErrGeneral ) ); + } + } + } + if(rec) + { + rec->SetObsoleteL(); + } + } + TInt pos = 0; + CSipSecAgreeRecord* rec = NextRecord( pos ); + __ASSERT_ALWAYS( rec, User::Leave( KErrNotFound ) ); + + CSipSecAgreeRecord* newRecord = + CSipSecAgreeRecord::NewLC( iStates, *this, rec->TransportParams() ); + +#ifdef CPPUNIT_TEST + if ( !rec->iObjCtr->iFeedBack->iRcrdCtrl2 ) + { + rec->iObjCtr->iFeedBack->iRcrdCtrl2 = newRecord->iObjCtr; + } + else if ( !rec->iObjCtr->iFeedBack->iRcrdCtrl3 ) + { + rec->iObjCtr->iFeedBack->iRcrdCtrl3 = newRecord->iObjCtr; + } + else if ( !rec->iObjCtr->iFeedBack->iRcrdCtrl4 ) + { + rec->iObjCtr->iFeedBack->iRcrdCtrl4 = newRecord->iObjCtr; + } +#endif + iSecAgreeRecords.AppendL( newRecord ); + CleanupStack::Pop( newRecord ); + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::ApplyRulesL +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::ApplyRulesL( + RPointerArray& aSecurityVerify ) + { + TInt pos( 0 ); + CSipSecAgreeRecord* record( NULL ); + while ( ( record = NextRecord( pos ) ) != NULL ) + { + record->ProcessSecVerifyL( aSecurityVerify ); + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::SetAuthKeyL +// ---------------------------------------------------------------------------- +// +TBool CSipSecAgreeContext::SetAuthKeyL( const TDesC8& aAuthKey ) + { + TBool ret( EFalse ); + TInt pos( 0 ); + CSipSecAgreeRecord* record( NULL ); + while ( ( record = NextRecord( pos ) ) != NULL ) + { + ret |= record->AuthKeyL( aAuthKey ); + } + return ret; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::AuthKeyFailedL +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::AuthKeyFailedL() + { + // Reverse order since call might lead to deletion of record + TInt lastIndex( iSecAgreeRecords.Count() - 1 ); + for ( TInt i = lastIndex; i >= 0; --i ) + { + if ( !iSecAgreeRecords[ i ]->IsObsolete() ) + { + iSecAgreeRecords[ i ]->AuthKeyFailedL(); + } + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::ClearL +// Affects also obsolete records. +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::ClearL() + { + iClearOrdered = ETrue; + + // Reverse order since call might lead to deletion of record, also whole + // context (this) will be removed if clearing leads to immediate deletion + // of all records. + TInt lastIndex( iSecAgreeRecords.Count() - 1 ); + for ( TInt i = lastIndex; i >= 0; i-- ) + { + iSecAgreeRecords[ i ]->ClearSaL(); + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::CancelPendingOps +// Affects also obsolete records. +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::CancelPendingOps( + const MSIPSecSecurityMechanismObserver* aObserver ) + { + if ( iObserver && iObserver == aObserver ) + { + // Observer cannot be used anymore + iObserver = NULL; + for ( TInt i = 0; i < iSecAgreeRecords.Count(); ++i ) + { + iSecAgreeRecords[ i ]->CancelPendingOps(); + } + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::SADBAddMsgReceived +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::SADBAddMsgReceived( TUint aMsgSeq, TInt aError ) + { + TInt pos( 0 ); + CSipSecAgreeRecord* record( NULL ); + while ( ( record = NextRecord( pos ) ) != NULL ) + { + record->SADBAddMsgReceived( aMsgSeq, aError ); + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::RemovalCompleted +// Affects also obsolete records. +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::RemovalCompleted( TUint32 aTransportId ) + { + for ( TInt i = 0; i < iSecAgreeRecords.Count(); ++i ) + { + iSecAgreeRecords[ i ]->RemovalCompleted( aTransportId ); + } + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::DeleteRecord +// Affects also obsolete records. +// ---------------------------------------------------------------------------- +// +void CSipSecAgreeContext::DeleteRecord( CSipSecAgreeRecord* aRecord ) + { + TInt i = iSecAgreeRecords.Find( aRecord ); + iSecAgreeRecords.Remove( i ); + iSecAgreeRecords.Compress(); + delete aRecord; + } + +// ---------------------------------------------------------------------------- +// CSipSecAgreeContext::NextRecord +// ---------------------------------------------------------------------------- +// +CSipSecAgreeRecord* CSipSecAgreeContext::NextRecord( TInt& aPos ) const + { + for ( TInt i = aPos; i < iSecAgreeRecords.Count(); ++i ) + { + if ( !iSecAgreeRecords[ i ]->IsObsolete() ) + { + // Set aPos point to next record + aPos = i + 1; + return iSecAgreeRecords[ i ]; + } + } + return NULL; + } + +// End of File