realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/sipsecdigestcache.cpp
changeset 0 307788aac0a8
equal deleted inserted replaced
-1:000000000000 0:307788aac0a8
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Name          : sipsecdigestcache.cpp
       
    15 // Part of       : SIPSec
       
    16 // Version       : SIP/6.0
       
    17 //
       
    18 
       
    19 
       
    20 
       
    21 #include "SipLogs.h"
       
    22 #include "siperr.h"
       
    23 #include "SipAssert.h"
       
    24 #include "sipsecdigestcache.h"
       
    25 #include "CSIPSecDigestCacheEntry.h"
       
    26 #include "CSIPSecDigestObserver.h"
       
    27 #include "CSIPSecUserRecord.h"
       
    28 #include "CSIPSecSIMRecord.h"
       
    29 #include "CSIPSecCredentials.h"
       
    30 #include "CSIPSecChallengeAKA.h"
       
    31 #include "RSIPSecChallengeResolver.h"
       
    32 #include "MSIPSecUser.h"
       
    33 #include "sipstrings.h"
       
    34 #include "sipstrconsts.h"
       
    35 #include "siprequest.h"
       
    36 #include "sipresponse.h"
       
    37 #include "sipsecdigestcontext.h"
       
    38 #include "sipauthenticateheaderbase.h"
       
    39 
       
    40 
       
    41 const TInt TSIPSecDigestCacheEntryIterator::iSIPSecOffset =
       
    42 	_FOFF( TSIPSecDigestCacheEntryIterator, iLink );
       
    43 
       
    44 // ============================ MEMBER FUNCTIONS ===============================
       
    45 
       
    46 
       
    47 // ----------------------------------------------------------------------------
       
    48 // CSIPSecDigestCache::NewL
       
    49 // ----------------------------------------------------------------------------
       
    50 //
       
    51 CSIPSecDigestCache* CSIPSecDigestCache::NewL( MTimerManager& aTimerManager )
       
    52 	{
       
    53 	CSIPSecDigestCache* self = NewLC( aTimerManager );
       
    54 	CleanupStack::Pop( self );
       
    55 	return self;
       
    56 	}
       
    57 
       
    58 // ----------------------------------------------------------------------------
       
    59 // CSIPSecDigestCache::NewLC
       
    60 // ----------------------------------------------------------------------------
       
    61 //		
       
    62 CSIPSecDigestCache* CSIPSecDigestCache::NewLC( MTimerManager& aTimerManager )
       
    63 	{
       
    64 	CSIPSecDigestCache* self =
       
    65 		new ( ELeave ) CSIPSecDigestCache( aTimerManager );
       
    66 	CleanupStack::PushL( self );
       
    67 	return self;
       
    68 	}
       
    69 
       
    70 // ----------------------------------------------------------------------------
       
    71 // CSIPSecDigestCache
       
    72 // ----------------------------------------------------------------------------
       
    73 //	
       
    74 CSIPSecDigestCache::CSIPSecDigestCache( MTimerManager& aTimerManager ) :
       
    75 	iProxyList( CSIPSecDigestCacheEntry::iSIPSecOffset ),
       
    76 	iProxyListIter( iProxyList ),
       
    77 	iEndpointList( CSIPSecDigestCacheEntry::iSIPSecOffset ),
       
    78 	iEndpointListIter( iEndpointList ),
       
    79 	iCredentialsList( CSIPSecUserRecord::iSIPSecOffset ),
       
    80 	iCredentialsListIter( iCredentialsList ),
       
    81 #ifdef CPPUNIT_TEST
       
    82 	// Use granularity 1 to make each append operation to allocate memory.
       
    83   	iDigestObservers( 1 ),
       
    84 #endif
       
    85 	iTimerManager( aTimerManager )
       
    86 	{
       
    87 	}	
       
    88 
       
    89 // ----------------------------------------------------------------------------
       
    90 // ~CSIPSecDigestCache
       
    91 // ----------------------------------------------------------------------------
       
    92 //	
       
    93 CSIPSecDigestCache::~CSIPSecDigestCache()
       
    94 	{
       
    95 	RemoveAllEntries();
       
    96 	RemoveAllCredentials();
       
    97 	iDigestObservers.ResetAndDestroy();
       
    98 	}
       
    99 
       
   100 // ----------------------------------------------------------------------------
       
   101 // CSIPSecDigestCache::InitializeIterator
       
   102 // ----------------------------------------------------------------------------
       
   103 //
       
   104 void
       
   105 CSIPSecDigestCache::InitializeIterator( TSIPSecDigestCacheIterator& aIterator )
       
   106     {
       
   107     iProxyListIter.SetToFirst();
       
   108     iEndpointListIter.SetToFirst();
       
   109 
       
   110     aIterator.iList.Reset();
       
   111     aIterator.iList.AddLast( iProxyListIter );
       
   112     aIterator.iList.AddLast( iEndpointListIter );
       
   113     aIterator.iListIterator.SetToFirst();
       
   114     }
       
   115 	
       
   116 // ----------------------------------------------------------------------------
       
   117 // CSIPSecDigestCache::AddEntry
       
   118 // ----------------------------------------------------------------------------
       
   119 //
       
   120 void CSIPSecDigestCache::AddEntry( CSIPSecDigestCacheEntry* aCacheEntry )
       
   121 	{
       
   122 	__SIP_ASSERT_RETURN( aCacheEntry, KErrArgument );
       
   123 	__SIP_ASSERT_RETURN( !IsEntryInCache( *aCacheEntry ), KErrAlreadyExists );
       
   124 
       
   125 	SelectCache( *aCacheEntry ).AddLast( *aCacheEntry );
       
   126 	}
       
   127 
       
   128 // ----------------------------------------------------------------------------
       
   129 // CSIPSecDigestCache::RemoveEntry
       
   130 // ----------------------------------------------------------------------------
       
   131 //
       
   132 void CSIPSecDigestCache::RemoveEntry( CSIPSecDigestCacheEntry& aCacheEntry )
       
   133 	{
       
   134 	__SIP_ASSERT_RETURN( IsEntryInCache( aCacheEntry ), KErrNotFound );
       
   135 
       
   136 	aCacheEntry.UserData().CredentialsDetach();
       
   137     SelectCache( aCacheEntry ).Remove( aCacheEntry );
       
   138 	delete &aCacheEntry;
       
   139 	}
       
   140 
       
   141 // ----------------------------------------------------------------------------
       
   142 // CSIPSecDigestCache::RemoveCacheEntry
       
   143 // ----------------------------------------------------------------------------
       
   144 //
       
   145 TBool CSIPSecDigestCache::RemoveCacheEntry( CSIPSecDigestCacheEntry& aEntry,
       
   146 											const MSIPSecUser& aUser )
       
   147 	{
       
   148 	CSIPSecUserRecord& record = aEntry.UserData();
       
   149     RemoveEntry( aEntry );
       
   150 	if ( record.CredentialsAttached() )
       
   151 		{
       
   152 		ChangeRecordUserIfNeeded( record, aUser );
       
   153 		return EFalse;
       
   154 		}
       
   155 
       
   156 	__SIP_LOG( "SIPSecDigestCache:RemoveCacheEntry record not used" )
       
   157 	__SIP_ASSERT_RETURN_VALUE( IsCredentialsInList( record ), KErrNotFound );
       
   158 	iCredentialsList.Remove( record );
       
   159 	delete &record;
       
   160 	return ETrue;
       
   161 	}
       
   162 
       
   163 // ----------------------------------------------------------------------------
       
   164 // CSIPSecDigestCache::IsEntryInCache
       
   165 // ----------------------------------------------------------------------------
       
   166 //
       
   167 TBool CSIPSecDigestCache::IsEntryInCache( CSIPSecDigestCacheEntry& aCacheEntry )
       
   168 	{
       
   169     TSIPSecDigestCacheEntryIterator entryIterator =
       
   170 		TSIPSecDigestCacheEntryIterator( SelectCache( aCacheEntry ) );
       
   171 
       
   172 	CSIPSecDigestCacheEntry* entry( NULL );
       
   173 	TBool found( EFalse );
       
   174 	while ( !found && ( entry = entryIterator.Next() ) != NULL )
       
   175 		{
       
   176 		found = ( entry == &aCacheEntry );
       
   177 		}
       
   178 	return found;
       
   179 	}
       
   180 
       
   181 // ----------------------------------------------------------------------------
       
   182 // CSIPSecDigestCache::SelectCache
       
   183 // ----------------------------------------------------------------------------
       
   184 //
       
   185 TSglQue< CSIPSecDigestCacheEntry >&
       
   186 CSIPSecDigestCache::SelectCache( const CSIPSecDigestCacheEntry& aCacheEntry )
       
   187 	{
       
   188 	if ( aCacheEntry.Type() == CSIPSecDigest::EEndPoint )
       
   189 		{
       
   190 		return iEndpointList;
       
   191 		}
       
   192 	return iProxyList;
       
   193 	}
       
   194 
       
   195 // ----------------------------------------------------------------------------
       
   196 // CSIPSecDigestCache::AddUserCredentials
       
   197 // ----------------------------------------------------------------------------
       
   198 //		
       
   199 void CSIPSecDigestCache::AddUserCredentials( CSIPSecUserRecord* aCredentials )
       
   200 	{
       
   201 	__SIP_ASSERT_RETURN( aCredentials, KErrArgument );
       
   202 	__SIP_ASSERT_RETURN( !IsCredentialsInList( *aCredentials ),
       
   203 						 KErrAlreadyExists );
       
   204     iCredentialsList.AddLast( *aCredentials );
       
   205 	}
       
   206 
       
   207 // ----------------------------------------------------------------------------
       
   208 // CSIPSecDigestCache::SearchRecordForResponse
       
   209 // Cache can have only one entry with matching MSIPSecUser and realm.
       
   210 // ----------------------------------------------------------------------------
       
   211 //
       
   212 CSIPSecUserRecord*
       
   213 CSIPSecDigestCache::SearchRecordForResponse( const TDesC8& aRealm,
       
   214 			  					  			 const MSIPSecUser& aUser,
       
   215 			  					  			 TRegistrationId aRegistrationId )
       
   216 	{
       
   217 	__ASSERT_ALWAYS( aRealm.Length() > 0,
       
   218 		User::Panic( _L( "DigestCache:SearchRecForResp" ), KErrArgument ) );
       
   219 
       
   220 	CSIPSecUserRecord* record( NULL );
       
   221 	iCredentialsListIter.SetToFirst();
       
   222 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   223 		{
       
   224 		if ( record->IsSameRealm( aRealm ) &&
       
   225 			 record->CompareUser( aUser, aRegistrationId ) )
       
   226 			{
       
   227 			return record;
       
   228 			}
       
   229 		}
       
   230 
       
   231 	return NULL;
       
   232 	}
       
   233 
       
   234 // ----------------------------------------------------------------------------
       
   235 // CSIPSecDigestCache::SearchRecord
       
   236 // ----------------------------------------------------------------------------
       
   237 //
       
   238 CSIPSecUserRecord*
       
   239 CSIPSecDigestCache::SearchRecord( const TDesC8& aRealm,
       
   240 							      TTransactionId aTransactionId )
       
   241 	{
       
   242 	__ASSERT_ALWAYS( aRealm.Length() > 0,
       
   243 		User::Panic( _L( "DigestCache:SearchRec(id)" ), KErrArgument ) );
       
   244 
       
   245 	CSIPSecUserRecord* record( NULL );
       
   246 	iCredentialsListIter.SetToFirst();
       
   247 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   248 		{
       
   249 		if ( record->IsSameRealm( aRealm ) &&
       
   250 			 record->TransactionIdPassedToClient() == aTransactionId )
       
   251 			{
       
   252 			return record;
       
   253 			}
       
   254 		}
       
   255 
       
   256 	return NULL;
       
   257 	}
       
   258 
       
   259 // ----------------------------------------------------------------------------
       
   260 // CSIPSecDigestCache::SearchRecord
       
   261 // ----------------------------------------------------------------------------
       
   262 //
       
   263 CSIPSecUserRecord* CSIPSecDigestCache::SearchRecord( const TDesC8& aRealm,
       
   264 			  					  					 const MSIPSecUser& aUser )
       
   265 	{
       
   266 	__ASSERT_ALWAYS( aRealm.Length() > 0,
       
   267 		User::Panic( _L( "DigestCache:SearchRec(user)" ), KErrArgument ) );
       
   268 
       
   269 	CSIPSecUserRecord* record( NULL );
       
   270 	iCredentialsListIter.SetToFirst();
       
   271 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   272 		{
       
   273 		if ( record->IsSameRealm( aRealm ) && &aUser == &record->SIPSecUser() )
       
   274 			{
       
   275 			return record;
       
   276 			}
       
   277 		}
       
   278 
       
   279 	return NULL;
       
   280 	}
       
   281 
       
   282 // ----------------------------------------------------------------------------
       
   283 // CSIPSecDigestCache::RemoveAllEntries
       
   284 // ----------------------------------------------------------------------------
       
   285 //
       
   286 void CSIPSecDigestCache::RemoveAllEntries()
       
   287 	{
       
   288 	RemoveAllEntriesFromList( iProxyList );
       
   289 	RemoveAllEntriesFromList( iEndpointList );
       
   290 	}
       
   291 
       
   292 // ----------------------------------------------------------------------------
       
   293 // CSIPSecDigestCache::RemoveAllEntriesFromList
       
   294 // ----------------------------------------------------------------------------
       
   295 //
       
   296 void CSIPSecDigestCache::RemoveAllEntriesFromList(
       
   297 	TSglQue<CSIPSecDigestCacheEntry>& aList )
       
   298 	{
       
   299 	if ( !aList.IsEmpty() )
       
   300 		{
       
   301 		CSIPSecDigestCacheEntry* entry( NULL );
       
   302     	TSIPSecDigestCacheEntryIterator entryIterator =
       
   303     		TSIPSecDigestCacheEntryIterator( aList );
       
   304 
       
   305 		while ( ( entry = entryIterator.Next() ) != NULL )
       
   306 			{
       
   307 			aList.Remove( *entry );
       
   308 			delete entry;
       
   309 			}
       
   310 		}
       
   311 	}
       
   312 
       
   313 // ----------------------------------------------------------------------------
       
   314 // CSIPSecDigestCache::RemoveAllCredentials
       
   315 // ----------------------------------------------------------------------------
       
   316 //		
       
   317 void CSIPSecDigestCache::RemoveAllCredentials()
       
   318 	{
       
   319 	if ( !iCredentialsList.IsEmpty() )
       
   320 		{
       
   321 		CSIPSecUserRecord* record( NULL );
       
   322 		iCredentialsListIter.SetToFirst();
       
   323 		while ( ( record = iCredentialsListIter++ ) != NULL )
       
   324 			{
       
   325 			iCredentialsList.Remove( *record );
       
   326 			delete record;
       
   327 			}
       
   328 		}		
       
   329 	}
       
   330 	
       
   331 // ----------------------------------------------------------------------------
       
   332 // CSIPSecDigestCache::IsCredentialsInList
       
   333 // ----------------------------------------------------------------------------
       
   334 //
       
   335 TBool CSIPSecDigestCache::IsCredentialsInList(
       
   336 	const CSIPSecUserRecord& aCredentials )
       
   337 	{
       
   338 	if ( !iCredentialsList.IsEmpty() )
       
   339 		{
       
   340 		CSIPSecUserRecord* record( NULL );
       
   341 		iCredentialsListIter.SetToFirst();
       
   342 		while ( ( record = iCredentialsListIter++ ) != NULL )
       
   343 			{
       
   344 			if ( record == &aCredentials )
       
   345 				{
       
   346 				return ETrue;
       
   347 				}
       
   348 			}
       
   349 		}
       
   350 	return EFalse;
       
   351 	}
       
   352 
       
   353 // ----------------------------------------------------------------------------
       
   354 // CSIPSecDigestCache::ClearCache
       
   355 // ----------------------------------------------------------------------------
       
   356 //
       
   357 void CSIPSecDigestCache::ClearCache( const MSIPSecUser& aUser )
       
   358 	{
       
   359 	RemoveUsedEntry( iProxyList, aUser );
       
   360 	RemoveUsedEntry( iEndpointList, aUser );
       
   361 	}
       
   362 
       
   363 // ----------------------------------------------------------------------------
       
   364 // CSIPSecDigestCache::RemoveUsedEntry
       
   365 // ----------------------------------------------------------------------------
       
   366 //
       
   367 void
       
   368 CSIPSecDigestCache::RemoveUsedEntry( TSglQue< CSIPSecDigestCacheEntry >& aList,
       
   369 								     const MSIPSecUser& aUser )
       
   370 	{
       
   371 	if ( !aList.IsEmpty() )
       
   372         {
       
   373         CSIPSecDigestCacheEntry* entry( NULL );
       
   374     	TSIPSecDigestCacheEntryIterator entryIter =
       
   375     		TSIPSecDigestCacheEntryIterator( aList );
       
   376 
       
   377         while ( ( entry = entryIter.Next() ) != NULL )
       
   378             {
       
   379             // When removing cache items, do NOT compare trusted user
       
   380 			if ( &entry->SIPSecUser() == &aUser )
       
   381 		        {
       
   382 		        RemoveCacheEntry( *entry, aUser );
       
   383 		        }
       
   384             }
       
   385         }
       
   386 	}
       
   387 
       
   388 // ----------------------------------------------------------------------------
       
   389 // CSIPSecDigestCache::ClearCache
       
   390 // ----------------------------------------------------------------------------
       
   391 //
       
   392 void CSIPSecDigestCache::ClearCache( CSIPSecUserRecord& aCredentials,
       
   393 									 TBool aAKAOnly )
       
   394 	{
       
   395 	RemoveMatchingEntry( iProxyList, aCredentials, aAKAOnly );
       
   396 	RemoveMatchingEntry( iEndpointList, aCredentials, aAKAOnly );
       
   397 	}
       
   398 
       
   399 // ----------------------------------------------------------------------------
       
   400 // CSIPSecDigestCache::RemoveMatchingEntry
       
   401 // ----------------------------------------------------------------------------
       
   402 //
       
   403 void CSIPSecDigestCache::RemoveMatchingEntry(
       
   404 	TSglQue< CSIPSecDigestCacheEntry >& aList,
       
   405 	CSIPSecUserRecord& aCredentials,
       
   406 	TBool aAKAOnly )
       
   407 	{
       
   408 	if ( !aList.IsEmpty() )
       
   409         {
       
   410         CSIPSecDigestCacheEntry* entry( NULL );
       
   411     	TSIPSecDigestCacheEntryIterator entryIter =
       
   412     		TSIPSecDigestCacheEntryIterator( aList );
       
   413 
       
   414 		while ( ( entry = entryIter.Next() ) != NULL )
       
   415 			{
       
   416 			if ( entry->HoldsUserData( aCredentials ) &&
       
   417 				 ( !aAKAOnly ||
       
   418 				   ( static_cast< CSIPSecCredentials* >( entry )->Challenge().
       
   419 				       Algorithm().AlgorithmName() ==
       
   420 				           CSIPSecChallengeAKA::SupportedAlgorithm() ) ) )
       
   421 			    {
       
   422 				if ( RemoveCacheEntry( *entry, entry->SIPSecUser() ) )
       
   423 					{
       
   424 					// Removed aCredentials, nothing refers to it, so exit loop
       
   425 					return;
       
   426 					}
       
   427 			    }
       
   428 			}
       
   429         }
       
   430 	}
       
   431 
       
   432 // ----------------------------------------------------------------------------
       
   433 // CSIPSecDigestCache::ClearAKAEntriesWithOldRealm
       
   434 // ----------------------------------------------------------------------------
       
   435 //
       
   436 void CSIPSecDigestCache::ClearAKAEntriesWithOldRealm( const TDesC8& aRealm )
       
   437 	{
       
   438 	CSIPSecUserRecord* record( NULL );
       
   439 	iCredentialsListIter.SetToFirst();
       
   440 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   441 		{
       
   442 		if ( !record->IsSameRealm( aRealm ) )
       
   443 			{
       
   444 			ClearCache( *record, ETrue );
       
   445 			}
       
   446 		}
       
   447 	}
       
   448 
       
   449 // ----------------------------------------------------------------------------
       
   450 // CSIPSecDigestCache::RegisterObserverL
       
   451 // Check if aObserver has a matching CSIPSecDigestObserver. If not, create
       
   452 // CSIPSecDigestObserver for it. Each SIP response has its own aObserver.
       
   453 // ----------------------------------------------------------------------------
       
   454 //
       
   455 CSIPSecDigestObserver* CSIPSecDigestCache::RegisterObserverL(
       
   456 	MSIPSecSecurityMechanismObserver& aObserver,
       
   457 	CSIPSecUserRecord& aUserData )
       
   458 	{
       
   459     CSIPSecDigestObserver* observer( NULL );
       
   460     TInt i( 0 );
       
   461     while ( !observer && i < iDigestObservers.Count() )
       
   462     	{
       
   463     	observer = iDigestObservers[ i++ ];
       
   464     	observer = observer->HasObserver( aObserver ) ? observer : NULL;
       
   465     	}
       
   466 
       
   467     if ( !observer )
       
   468         {
       
   469         observer = aUserData.CreateObserverL( aObserver );
       
   470         CleanupStack::PushL( observer );
       
   471     	iDigestObservers.AppendL( observer );
       
   472     	CleanupStack::Pop( observer );
       
   473         }
       
   474 
       
   475 	return observer;
       
   476 	}
       
   477 
       
   478 // ----------------------------------------------------------------------------
       
   479 // CSIPSecDigestCache::CancelPendingOperations
       
   480 // ----------------------------------------------------------------------------
       
   481 //
       
   482 void CSIPSecDigestCache::CancelPendingOperations(
       
   483 	MSIPSecSecurityMechanismObserver* aObserver )
       
   484 	{
       
   485 	CSIPSecUserRecord* record( NULL );
       
   486 	iCredentialsListIter.SetToFirst();
       
   487 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   488 		{
       
   489 		record->CancelPendingOperations( aObserver );
       
   490 		}
       
   491 
       
   492 	CleanObservers();
       
   493 	}
       
   494 
       
   495 // ----------------------------------------------------------------------------
       
   496 // CSIPSecDigestCache::Cancel
       
   497 // ----------------------------------------------------------------------------
       
   498 //
       
   499 TInt CSIPSecDigestCache::Cancel( TTransactionId aTransactionId,
       
   500                                  const TDesC8& aRealm,
       
   501                                  const MSIPSecUser* aTrustedUser )
       
   502 	{
       
   503 	if ( aRealm.Length() == 0 )
       
   504     	{
       
   505     	return KErrArgument;
       
   506     	}
       
   507 
       
   508 	TInt status( KErrNotFound );
       
   509 	CSIPSecUserRecord* record( NULL );
       
   510 	iCredentialsListIter.SetToFirst();
       
   511 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   512 		{
       
   513 		if ( record->IsSameRealm( aRealm ) &&
       
   514 			 ( record->TransactionIdPassedToClient() == aTransactionId || 
       
   515 			   &record->SIPSecUser() == aTrustedUser ) )
       
   516 			{
       
   517 			status = KErrNone; // At least one found
       
   518             record->CancelPendingOperations( NULL /* cancel all */ );
       
   519 			}
       
   520 		}
       
   521 
       
   522 	CleanObservers();
       
   523 	return status;
       
   524 	}
       
   525 
       
   526 // ----------------------------------------------------------------------------
       
   527 // CSIPSecDigestCache::Remove
       
   528 // ----------------------------------------------------------------------------
       
   529 //
       
   530 TInt CSIPSecDigestCache::Remove( const TDesC8& aRealm )
       
   531 	{
       
   532 	if ( aRealm.Length() == 0 )
       
   533     	{
       
   534     	return KErrArgument;
       
   535     	}
       
   536 
       
   537 	TInt status( KErrNotFound );
       
   538 	CSIPSecUserRecord* record( NULL );
       
   539 	iCredentialsListIter.SetToFirst();
       
   540 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   541 		{
       
   542 		if ( record->IsSameRealm( aRealm ) )
       
   543 			{
       
   544 			status = KErrNone; // At least one found
       
   545 	        // Remove entries pointing to record, then remove record.
       
   546 			ClearCache( *record, EFalse );
       
   547 			}
       
   548 		}
       
   549 
       
   550 	CleanObservers();
       
   551 	return status;
       
   552 	}
       
   553 
       
   554 // ----------------------------------------------------------------------------
       
   555 // CSIPSecDigestCache::CountResponses
       
   556 // There can be just one record per realm/transaction id pair, as many SIPSec
       
   557 // users can't have the same transaction id. Cache has just one IMS record.
       
   558 // Compare the real transaction ids, regardless of the value returned by
       
   559 // MSIPSecUser::PassOnlyRealmsToUser().
       
   560 // ----------------------------------------------------------------------------
       
   561 //
       
   562 TInt CSIPSecDigestCache::CountResponses( CSIPResponse& aResponse,
       
   563 									     CSIPRequest& aRequest,
       
   564 									     TTransactionId aTransactionId,
       
   565 									     RStringF aDefaultAlgorithm )
       
   566 	{
       
   567 	TInt status( KErrNone );
       
   568 
       
   569 	RStringF alg;
       
   570 	RStringF dummyQop;
       
   571 	RSIPSecChallengeResolver::GetDigestParamsFromSecurityServer( aResponse,
       
   572 									   			     			 alg,
       
   573 									   				 			 dummyQop );
       
   574 	CSIPSecUserRecord* record( NULL );
       
   575 	iCredentialsListIter.SetToFirst();
       
   576 	while ( ( record = iCredentialsListIter++ ) != NULL )
       
   577 		{
       
   578 		if ( record->Type() == CSIPSecUserRecord::EIMS &&
       
   579 			 record->TransactionId() == aTransactionId )
       
   580 			{			
       
   581 			TBool match( EFalse );
       
   582 	    	if ( !HandleChallenges( aResponse,
       
   583 	    						    alg,
       
   584 	    						    aDefaultAlgorithm,
       
   585 	    						    record->Realm(),
       
   586 	    						    match ) )
       
   587 				{
       
   588 				__SIP_ASSERT_RETURN_VALUE( !match, KErrAlreadyExists );
       
   589 				match = HandleAuthorizations( aRequest,
       
   590 											  alg,
       
   591 											  aDefaultAlgorithm,
       
   592 											  record->Realm() );
       
   593 				}
       
   594 			if ( match &&
       
   595 				 static_cast< CSIPSecSIMRecord* >( record )->
       
   596 				 	UpdateMessageCounter( aResponse.ResponseCode() ) )
       
   597 				{
       
   598 				status = KErrSIPForbidden;
       
   599 				}
       
   600 			}
       
   601 		}
       
   602 	return status;
       
   603 	}
       
   604 
       
   605 // ----------------------------------------------------------------------------
       
   606 // CSIPSecDigestCache::CleanObservers
       
   607 // ----------------------------------------------------------------------------
       
   608 //
       
   609 void CSIPSecDigestCache::CleanObservers()
       
   610 	{
       
   611     TInt i( 0 );
       
   612     while ( i < iDigestObservers.Count() )
       
   613     	{
       
   614     	CSIPSecDigestObserver* observer = iDigestObservers[ i ];
       
   615     	if ( observer->IsCompleted() )
       
   616     	    {
       
   617     	    iDigestObservers.Remove( i );
       
   618     	    delete observer;
       
   619     	    }
       
   620         else
       
   621             {
       
   622             ++i;
       
   623             }
       
   624     	}
       
   625 	}
       
   626 
       
   627 // -----------------------------------------------------------------------------
       
   628 // CSIPSecDigestCache::HandleChallenges
       
   629 // -----------------------------------------------------------------------------
       
   630 //
       
   631 TBool CSIPSecDigestCache::HandleChallenges( CSIPResponse& aResponse,
       
   632 										    RStringF aAlgorithm,	
       
   633 										    RStringF aDefaultAlgorithm,									  
       
   634 											const TDesC8& aRealm,
       
   635 											TBool& aMatch ) const
       
   636 	{
       
   637 	TBool proxyChallenges( EFalse );
       
   638 	TBool endpointChallenges( EFalse );
       
   639 
       
   640 	aMatch = HandleAuthHeaders( aResponse,
       
   641 				aAlgorithm,
       
   642 				aDefaultAlgorithm,
       
   643 				SIPStrings::StringF( SipStrConsts::EProxyAuthenticateHeader ),
       
   644 				aRealm,
       
   645 				ETrue,
       
   646 				proxyChallenges ) ||
       
   647 			 HandleAuthHeaders( aResponse,
       
   648 				aAlgorithm,
       
   649 				aDefaultAlgorithm,
       
   650 				SIPStrings::StringF( SipStrConsts::EWWWAuthenticateHeader ),
       
   651 				aRealm,
       
   652 				ETrue,
       
   653 				endpointChallenges );
       
   654 	return proxyChallenges || endpointChallenges;
       
   655 	}
       
   656 
       
   657 // -----------------------------------------------------------------------------
       
   658 // CSIPSecDigestCache::HandleAuthorizations
       
   659 // -----------------------------------------------------------------------------
       
   660 //
       
   661 TBool CSIPSecDigestCache::HandleAuthorizations( CSIPRequest& aRequest,
       
   662 										  	 	RStringF aAlgorithm,
       
   663 										  	 	RStringF aDefaultAlgorithm,
       
   664 										  		const TDesC8& aRealm ) const
       
   665 	{
       
   666 	TBool dummy( EFalse );
       
   667 	return HandleAuthHeaders( aRequest,
       
   668 				aAlgorithm,
       
   669 				aDefaultAlgorithm,
       
   670 				SIPStrings::StringF( SipStrConsts::EAuthorizationHeader ),
       
   671 				aRealm,
       
   672 				EFalse,
       
   673 				dummy ) ||
       
   674 		   HandleAuthHeaders( aRequest,
       
   675 				aAlgorithm,
       
   676 				aDefaultAlgorithm,
       
   677 				SIPStrings::StringF( SipStrConsts::EProxyAuthorizationHeader ),
       
   678 				aRealm,
       
   679 				EFalse,
       
   680 				dummy );
       
   681 	}
       
   682 
       
   683 // -----------------------------------------------------------------------------
       
   684 // CSIPSecDigestCache::HandleAuthHeaders
       
   685 // -----------------------------------------------------------------------------
       
   686 //
       
   687 TBool CSIPSecDigestCache::HandleAuthHeaders( CSIPMessage& aMessage,
       
   688 											 RStringF aAlgorithm,
       
   689 											 RStringF aDefaultAlgorithm,
       
   690 											 RStringF aHeaderName,
       
   691 											 const TDesC8& aRealm,
       
   692 											 TBool aCheckChallenges,
       
   693 											 TBool& aChallengeFound ) const
       
   694 	{
       
   695 	aChallengeFound = EFalse;
       
   696 	TBool match( EFalse );
       
   697 
       
   698 	if ( aMessage.HeaderCount( aHeaderName ) > 0 )
       
   699 		{
       
   700 		TSglQueIter< CSIPHeaderBase > headers = aMessage.Headers( aHeaderName );
       
   701     	while ( headers && !match )
       
   702     		{
       
   703 	        CSIPAuthHeaderBase* authHeader =
       
   704 	        	static_cast< CSIPAuthHeaderBase* >( headers++ );
       
   705 			if ( !aCheckChallenges ||
       
   706 				 RSIPSecChallengeResolver::IsValidDigestChallenge(
       
   707 				 	*authHeader ) )
       
   708 				{
       
   709 				aChallengeFound = ETrue;				
       
   710 				match =	CompareAKARealm( *authHeader,
       
   711 										 aRealm,
       
   712 										 aAlgorithm,
       
   713 										 aDefaultAlgorithm );
       
   714 				}
       
   715 	    	}
       
   716 		}
       
   717 	return match;
       
   718 	}
       
   719 
       
   720 // -----------------------------------------------------------------------------
       
   721 // CSIPSecDigestCache::CompareAKARealm
       
   722 // aAlgorithm may change in this function, but caller's algorithm must not.
       
   723 // -----------------------------------------------------------------------------
       
   724 //
       
   725 TBool CSIPSecDigestCache::CompareAKARealm( CSIPAuthHeaderBase& aHeader,
       
   726 										   const TDesC8& aCachedRealm,
       
   727 										   RStringF aAlgorithm,
       
   728 										   RStringF aDefaultAlgorithm ) const
       
   729 	{
       
   730 	RSIPSecChallengeResolver::SelectAlgorithm( aHeader,
       
   731 											   aDefaultAlgorithm,
       
   732 											   aAlgorithm );					   	   
       
   733 	return ( TSIPSecDigestContext::GetDesParam( aHeader,
       
   734 				SipStrConsts::ERealm ).Compare( aCachedRealm ) == 0 ) &&
       
   735 		   ( aAlgorithm == SIPStrings::StringF( SipStrConsts::EAKAv1MD5 ) );
       
   736 	}
       
   737 
       
   738 // -----------------------------------------------------------------------------
       
   739 // CSIPSecDigestCache::ChangeRecordUserIfNeeded
       
   740 // If none of the entries in iProxyList or iEndpointList that point to aRecord,
       
   741 // have the same SIPSec user as the aRecord, change aRecord's SIPSec user to be
       
   742 // any of the referring entries' SIPSec user.
       
   743 // -----------------------------------------------------------------------------
       
   744 //
       
   745 void CSIPSecDigestCache::ChangeRecordUserIfNeeded( CSIPSecUserRecord& aRecord,
       
   746 												   const MSIPSecUser& aUser )
       
   747 	{
       
   748 	// Do not compare trusted user
       
   749 	if ( &aRecord.User() == &aUser )
       
   750 		{
       
   751 		// Loop both proxy and endpoint caches.
       
   752 		// iProxyListIter and iEndpointListIter are already used by the code
       
   753 		// that calls ChangeRecordUserIfNeeded(), so use new iterators.
       
   754     	TSIPSecDigestCacheEntryIterator proxyListIter( iProxyList );
       
   755     	TSIPSecDigestCacheEntryIterator endpointListIter( iEndpointList );
       
   756 		TSIPSecDigestCacheIterator cacheIterator;
       
   757     	// Initialize iterators
       
   758     	proxyListIter.SetToFirst();
       
   759     	endpointListIter.SetToFirst();
       
   760     	cacheIterator.iList.Reset();
       
   761     	cacheIterator.iList.AddLast( proxyListIter );
       
   762     	cacheIterator.iList.AddLast( endpointListIter );
       
   763     	cacheIterator.iListIterator.SetToFirst();
       
   764 
       
   765 		const MSIPSecUser* sipSecUser( NULL );
       
   766 		CSIPSecDigestCacheEntry* entry( NULL );
       
   767 		while ( ( entry = cacheIterator.Next() ) != NULL )
       
   768 			{
       
   769 			if ( entry->HoldsUserData( aRecord ) )
       
   770 				{
       
   771 				if ( &entry->SIPSecUser() == &aUser )
       
   772 					{
       
   773 					return; // Same SIPSec user, no action needed
       
   774 					}
       
   775 				else
       
   776 					{
       
   777 					sipSecUser = &entry->SIPSecUser();
       
   778 					}
       
   779 				}
       
   780 			}
       
   781 
       
   782 		// Original SIPSec user no longer uses aRecord.
       
   783 		// Change SIPSec user to one of those still using it.
       
   784 		__ASSERT_DEBUG( sipSecUser != NULL,
       
   785 						User::Panic( _L( "DigestCache:ChangeRecUser" ),
       
   786 									 KErrNotFound ) );
       
   787 		if ( sipSecUser )
       
   788 			{
       
   789 			aRecord.SetUser( *sipSecUser );
       
   790 			}
       
   791 		}
       
   792 	}
       
   793 
       
   794 // ============================ MEMBER FUNCTIONS ===============================
       
   795 
       
   796 // ----------------------------------------------------------------------------
       
   797 // TSIPSecDigestCacheEntryIterator::TSIPSecDigestCacheEntryIterator
       
   798 // ----------------------------------------------------------------------------
       
   799 //
       
   800 TSIPSecDigestCacheEntryIterator::TSIPSecDigestCacheEntryIterator(
       
   801 	TSglQue<CSIPSecDigestCacheEntry>& aList ) :
       
   802     TSglQueIter<CSIPSecDigestCacheEntry>( aList ),
       
   803     iLink()
       
   804     {
       
   805     SetToFirst();
       
   806     }
       
   807 
       
   808 // ----------------------------------------------------------------------------
       
   809 // TSIPSecDigestCacheEntryIterator::Next
       
   810 // Return the next matching entry in the cache.
       
   811 // ----------------------------------------------------------------------------
       
   812 //
       
   813 CSIPSecDigestCacheEntry*
       
   814 TSIPSecDigestCacheEntryIterator::Next( TSIPSecPluginContext& aContext )
       
   815 	{
       
   816 	CSIPSecDigestCacheEntry* entry( NULL );
       
   817 
       
   818 	while ( ( entry = Next() ) != NULL )
       
   819  		{
       
   820  		if ( entry->Match( aContext ) )
       
   821  			{
       
   822  			return entry;
       
   823  			}
       
   824   		}
       
   825 
       
   826  	return NULL;
       
   827 	}
       
   828 
       
   829 // ----------------------------------------------------------------------------
       
   830 // TSIPSecDigestCacheEntryIterator::Next
       
   831 // ----------------------------------------------------------------------------
       
   832 //
       
   833 CSIPSecDigestCacheEntry* TSIPSecDigestCacheEntryIterator::Next()
       
   834 	{
       
   835     return ( *this )++;
       
   836 	}
       
   837 
       
   838 
       
   839 
       
   840 // ============================ MEMBER FUNCTIONS ===============================
       
   841 
       
   842 // ----------------------------------------------------------------------------
       
   843 // TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator
       
   844 // ----------------------------------------------------------------------------
       
   845 //
       
   846 TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator() :
       
   847     iList( TSIPSecDigestCacheEntryIterator::iSIPSecOffset ),
       
   848     iListIterator( TSglQueIter<TSIPSecDigestCacheEntryIterator>( iList ) ),
       
   849     iContext( NULL )
       
   850     {
       
   851     }
       
   852 
       
   853 // ----------------------------------------------------------------------------
       
   854 // TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator
       
   855 // ----------------------------------------------------------------------------
       
   856 //
       
   857 TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator(
       
   858 	TSIPSecPluginContext& aContext ) :
       
   859 	iList( TSIPSecDigestCacheEntryIterator::iSIPSecOffset ),
       
   860     iListIterator( TSglQueIter<TSIPSecDigestCacheEntryIterator>( iList ) ),
       
   861     iContext( &aContext )
       
   862     {    
       
   863     }
       
   864 
       
   865 // ----------------------------------------------------------------------------
       
   866 // TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator
       
   867 // ----------------------------------------------------------------------------
       
   868 //
       
   869 CSIPSecDigestCacheEntry* TSIPSecDigestCacheIterator::Next()
       
   870     {
       
   871     TSIPSecDigestCacheEntryIterator* iter( NULL );
       
   872     CSIPSecDigestCacheEntry* entry( NULL );
       
   873 
       
   874 	// Loop until an entry is found or both lists have been traversed
       
   875     while ( !entry && ( iter = iListIterator ) != NULL )
       
   876         {
       
   877         // Get next entry from current list
       
   878         entry = iContext ? iter->Next( *iContext ) : iter->Next();
       
   879 
       
   880         // If the current list has been exhausted, move to next list
       
   881         if ( !entry )
       
   882         	{
       
   883         	iter = ( iListIterator )++;
       
   884         	}
       
   885         }
       
   886 
       
   887     return entry;
       
   888 	}