os/security/cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 *
    16 */
    17 
    18 
    19 #include "CFSCertAppsServer.h"
    20 #include "CCertAppsSession.h"
    21 #include "CCertAppsConduit.h"
    22 #include "fstokencliserv.h"
    23 #include "fstokenutil.h"
    24 
    25 #include <certstorepatchdata.h>
    26 #include <certificateapps.h>
    27 #include <u32hal.h> 
    28 #include <e32svr.h>
    29 
    30 // Filename where all data is stored
    31 _LIT(KCertAppsFilename,"certclients.dat");
    32 _LIT(KCertAppsFile,"certclients*.dat");
    33 
    34 CFSCertAppsServer* CFSCertAppsServer::NewL()
    35 	{
    36 	CFSCertAppsServer* self = new (ELeave) CFSCertAppsServer();
    37 	CleanupStack::PushL(self);
    38 	self->ConstructL();
    39 	CleanupStack::Pop(self);
    40 	return self;
    41 	}
    42 
    43 CFSCertAppsServer::CFSCertAppsServer()
    44 	{
    45 	}
    46 
    47 void CFSCertAppsServer::ConstructL()
    48 	{
    49 	iConduit = CCertAppsConduit::NewL(*this);
    50 	
    51 	// Connect to the filesystem
    52 	User::LeaveIfError(iFs.Connect());
    53 
    54 	iPatchableConst = KAggregateCertStore;
    55 	
    56 	#ifdef __WINS__
    57 		// For the emulator allow the constant to be patched via epoc.ini
    58 		UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
    59 		(TAny*)"KAggregateCertStore", &iPatchableConst); // read emulator property (if present)
    60 	#endif		
    61 	
    62 	// Retrieves the store
    63 	OpenStoreL();
    64 	}
    65 
    66 CFSCertAppsServer::~CFSCertAppsServer()
    67 	{
    68 	delete iStore;
    69  	iFs.Close();
    70 	iClients.Close();
    71 	delete iConduit;
    72 	}
    73 
    74 CCertAppsSession* CFSCertAppsServer::CreateSessionL()
    75 	{
    76 	return CCertAppsSession::NewL(*iConduit); 
    77 	}
    78 
    79 void CFSCertAppsServer::AddL(const TCertificateAppInfo& aClient)
    80 	{
    81 	// see if application already exists. If so, then leave
    82 	
    83 	if (FindApplication(aClient.Id()))
    84 		{
    85 		User::Leave(KErrAlreadyExists);
    86 		}
    87 	User::LeaveIfError(iClients.Append(aClient));
    88 	TRAPD(err, ReplaceAndCommitL(-1));
    89 	if (err != KErrNone)
    90 		{
    91 		// We must remove the client from iClients if we didn't manage 
    92 		// to add it to the store
    93 		iClients.Remove(iClients.Count() - 1);
    94 		User::Leave(err);
    95 		}
    96 	}
    97 
    98 void CFSCertAppsServer::RemoveL(const TUid& aUid)
    99 	{
   100 	// Make sure the application for that uid exists
   101 	TInt i;
   102 	if (!FindApplication(aUid, &i))
   103 		{
   104 		User::Leave(KErrNotFound);
   105 		}
   106 
   107 	ReplaceAndCommitL(i);
   108 	
   109 	// We managed to remove it from the store, so we remove it from the
   110 	// iClients array
   111 	iClients.Remove(i);
   112 	}
   113 
   114 TInt CFSCertAppsServer::ApplicationCountL() const
   115 	{
   116 	return iClients.Count();
   117 	}
   118 
   119 void CFSCertAppsServer::ApplicationsL(RArray<TCertificateAppInfo>& aAppArray) const
   120 	{
   121 	// Make a copy of the array
   122 	TInt count = iClients.Count();
   123 
   124 	for (TInt i = 0; i < count; ++i)
   125 		{
   126 		aAppArray.AppendL(iClients[i]);
   127 		}
   128 	}
   129 
   130 void CFSCertAppsServer::ApplicationL(const TUid& aUid, TCertificateAppInfo& aInfo) const
   131 	{
   132 	const TCertificateAppInfo* app = FindApplication(aUid);
   133 
   134 	// leave if not found
   135 	if (!app)
   136 		{
   137 		User::Leave(KErrNotFound);
   138 		}
   139 
   140 	// make a copy and return to client
   141 	aInfo = *app;
   142 	}
   143 
   144 const TCertificateAppInfo* CFSCertAppsServer::FindApplication(const TUid& aUid, TInt* aIndex) const
   145 	{
   146 	// This helper function tries to find an application with the given
   147 	// Uid. It returns NULL if not found. aIndex returns the index into
   148 	// the array successful
   149 	const TCertificateAppInfo* retVal = NULL;
   150 	TInt end = iClients.Count();
   151 	for (TInt i = 0; i < end; ++i)
   152 		{
   153 		if (iClients[i].Id() == aUid)
   154 			{
   155 			// check if an index is required to be returned
   156 			if (aIndex)
   157 				{
   158 				*aIndex = i;
   159 				}
   160 			retVal = &iClients[i];
   161 			break;
   162 			}
   163 		}
   164 
   165 	return retVal;
   166 	}
   167 
   168 void CFSCertAppsServer::AggregateStoreFileL(const TDesC& aFile)
   169 	{
   170 	ASSERT(iPatchableConst);
   171 
   172 	// if patchable constant is enabled
   173 	// 1. open read-only permanent file store on each file.
   174 	// 2. open certificate client entry list of each store.
   175 	// 3. aggregate the entries.
   176 	RFile file;
   177 	User::LeaveIfError(file.Open(iFs, aFile, EFileRead));
   178 	CleanupClosePushL(file);
   179 	CPermanentFileStore* store = CPermanentFileStore::FromL(file);
   180 	// now owned by store
   181 	CleanupStack::Pop(&file); 
   182 	CleanupStack::PushL(store);
   183 
   184 	// Read id of cert list stream
   185 	TStreamId streamId;
   186 	RStoreReadStream stream;
   187 	stream.OpenLC(*store, store->Root());
   188 	stream >> streamId;
   189 	CleanupStack::PopAndDestroy(&stream);
   190 	
   191 	// Read the certificate's clients entry list
   192 	stream.OpenLC(*store, streamId);
   193 	TInt count = stream.ReadInt32L();
   194 	RArray<TCertificateAppInfo> entryList;
   195 	for (TInt i = 0 ; i < count ; i++)
   196 		{
   197 		TCertificateAppInfo clientInfo;
   198 		stream >> clientInfo;
   199 		entryList.AppendL(clientInfo);
   200 		}
   201 	CleanupStack::PopAndDestroy(&stream);
   202 	CleanupClosePushL(entryList);
   203 
   204 	MergeCertificateEntryListL(entryList);
   205 	// cleanup entryList and store instances.
   206 	CleanupStack::PopAndDestroy(2,store);		
   207 	}
   208 
   209 TBool CFSCertAppsServer::FindUid(const TUid& aUid)
   210 	{
   211 	TInt end = iClients.Count();
   212 	for (TInt i = 0; i < end; ++i)
   213 		{
   214 		if (iClients[i].Id() == aUid)
   215 			{
   216 			return ETrue;
   217 			}
   218 		}
   219 	return EFalse;
   220 	}
   221 
   222 void CFSCertAppsServer::MergeCertificateEntryListL(const RArray<TCertificateAppInfo>& aSourceList)
   223 	{
   224 	ASSERT(iPatchableConst);
   225 
   226 	// if patchable constant is enabled
   227 	TInt sourceCount = aSourceList.Count();
   228 	for(TInt i = 0; i < sourceCount; i++)
   229 		{
   230 		// compare if the uid pre-exists in the composite list.
   231 		if (!FindUid(aSourceList[i].Id()))
   232 			{
   233 			// Aggregation: append this entry to the composite list.
   234 			iClients.AppendL(aSourceList[i]);
   235 			}
   236 		// Eclipsing: Higher order store cert client entries with same UIDs take precedence over lower order  
   237 		// store cert client entries therefore the later are not included in the composite cert client entry list.
   238 		// Higher order store client entries are ones which are aggregated prior to other client entries. 
   239 		}
   240 	}
   241 
   242 void CFSCertAppsServer::OpenCompositeStoreL(const TDesC& aFilename)
   243 	{
   244 	ASSERT(iPatchableConst);
   245 
   246 	// 1. create a new empty certstore file under system drive with the name 'certclients.dat'. 
   247 	// 2. this will be the composite store and the instances 'iEntryList' and 'iStore' will be initialized with this.
   248 	// 3. make private rom drive path where certstore files are located.
   249 	// 4. collect the certstore file names in a list.
   250 	// 5. make private rom drive path on each file.
   251 	// 6. populate the composite store with certificate client entries present in rom drive certstores.
   252 	
   253 	// create a new empty certstore file 'certclients.dat' under system drive.
   254 	CreateStoreL(aFilename);	
   255 	// restore permanent store on it 
   256 	// this will be the composite store after complete aggregation. 
   257 	ReadStoreContentsL(aFilename);
   258 		
   259 	RBuf romFilename;
   260 	romFilename.CreateL(KMaxFilenameLength);
   261 	CleanupClosePushL(romFilename);
   262 	FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFile, romFilename);
   263 	CDir* filenameList = NULL;
   264 	User::LeaveIfError(iFs.GetDir(romFilename, KEntryAttNormal, ESortByName|EDescending, filenameList));
   265 	CleanupStack::PopAndDestroy(&romFilename);
   266 	CleanupStack::PushL(filenameList);
   267 	TInt count = filenameList->Count();
   268 	
   269 	// aggregate ROM stores iteratively 
   270 	for(TInt index = 0; index < count; index++)		
   271 		{
   272 		RBuf fileName;
   273 		fileName.CreateL(KMaxFileName);
   274 		CleanupClosePushL(fileName);	
   275 		FileUtils::MakePrivateROMFilenameL(iFs, ((*filenameList)[index]).iName, fileName);
   276 		// if there is any corrupt certstore present then we will simply ignore its
   277 		// aggregation and proceed with aggregating remaining stores.
   278 		TRAP_IGNORE(AggregateStoreFileL(fileName));
   279 		CleanupStack::PopAndDestroy(&fileName);	
   280 		}
   281 	// write the 'iClients' to the composite store.	
   282 	ReplaceAndCommitL(-1);	
   283 	CleanupStack::PopAndDestroy(filenameList);
   284 	}
   285 
   286 // this logic should be handled by a superclass or mixin
   287 void CFSCertAppsServer::OpenStoreL()
   288 	{
   289 	RBuf filename;
   290 	filename.CreateL(KMaxFilenameLength);
   291 	CleanupClosePushL(filename);		
   292 	FileUtils::MakePrivateFilenameL(iFs, KCertAppsFilename, filename);
   293 
   294 	// Attempt to open the store
   295 	// need to test opening corrupt store
   296 	TRAPD(err, ReadStoreContentsL(filename));
   297 
   298 	if (err == KErrNoMemory || err == KErrInUse)
   299 		{
   300 		User::Leave(err);
   301 		}
   302 	
   303 	if (err != KErrNone)
   304 		{
   305 		// Couldn't open RAM based store, copy from ROM	
   306 		FileUtils::EnsurePathL(iFs, filename);		
   307 	
   308 		if(iPatchableConst)
   309 			{
   310 			OpenCompositeStoreL(filename);
   311 			}
   312 		else
   313 			{
   314 			RBuf romFilename;
   315 			romFilename.CreateL(KMaxFilenameLength);
   316 			CleanupClosePushL(romFilename);			
   317 			FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFilename, romFilename);
   318 			
   319 			if (FileUtils::ExistsL(iFs, romFilename))
   320 				{
   321 				FileUtils::CopyL(iFs, romFilename, filename);
   322 				}
   323 			else
   324 				{
   325 				CreateStoreL(filename);
   326 				}
   327 			CleanupStack::PopAndDestroy(&romFilename);
   328 			//Retry open, and leave on failure
   329 			ReadStoreContentsL(filename);			
   330 			}
   331 		}
   332 	CleanupStack::PopAndDestroy(&filename);
   333 	ASSERT(iStore);
   334 	}
   335 
   336 void CFSCertAppsServer::ReadStoreContentsL(const TDesC& aFilename)
   337 	{
   338 	// Make sure the store is not read-only
   339 	User::LeaveIfError(iFs.SetAtt(aFilename, KEntryAttNormal, KEntryAttReadOnly));
   340 
   341 	RFile file;
   342 	User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileWrite));
   343 	CleanupClosePushL(file);
   344 	CPermanentFileStore* store = CPermanentFileStore::FromL(file);
   345 	CleanupStack::Pop(&file);
   346 	CleanupStack::PushL(store);
   347 
   348 	// now read the root stream to get the id of our main stream
   349 	RStoreReadStream readStream;
   350 	readStream.OpenLC(*store, store->Root());
   351 	readStream >> iId;	// This can leave
   352 	CleanupStack::PopAndDestroy(&readStream);
   353 
   354 	// finally, restore the stream which contains the client arrays.
   355 	// First long is the number of entries, then each entry 
   356 	readStream.OpenLC(*store, iId);
   357 	TInt count = readStream.ReadInt32L();
   358 	for (TInt i = 0; i < count; ++i)
   359 		{
   360 		TCertificateAppInfo clientInfo;
   361 		readStream >> clientInfo;
   362 		User::LeaveIfError(iClients.Append(clientInfo));
   363 		}
   364 	CleanupStack::PopAndDestroy(&readStream);
   365 
   366 	ASSERT(!iStore);
   367 	iStore = store;
   368 	CleanupStack::Pop(store);
   369 	}
   370 
   371 void CFSCertAppsServer::CreateStoreL(const TDesC& aFilename)
   372 	{
   373 	// If for some reason we can't complete the creation of the store, we want
   374 	// to be sure that we don't leave a half-constructed store on the device
   375 	// as we will then be in trouble when we try to open the store
   376 	TCleanupItem deleteStoreFile(DeleteStoreFile, this);
   377 	CleanupStack::PushL(deleteStoreFile);
   378 
   379 	iFs.Delete(aFilename); // ignore errors
   380 
   381 	RFile file;
   382 	User::LeaveIfError(file.Create(iFs, aFilename, EFileWrite));
   383 	CleanupClosePushL(file);
   384 	
   385 	CPermanentFileStore* store = CPermanentFileStore::NewL(file);
   386 	CleanupStack::Pop(&file); // now owned by store
   387 	CleanupStack::PushL(store);
   388 	store->SetTypeL(KPermanentFileStoreLayoutUid);
   389 
   390 	RStoreWriteStream clientsStream;
   391 	TStreamId id = clientsStream.CreateLC(*store);
   392 	WriteClientArrayL(clientsStream);
   393 	CleanupStack::PopAndDestroy(&clientsStream);
   394 
   395 	RStoreWriteStream rootStream;
   396 	TStreamId rootId = rootStream.CreateLC(*store);
   397 	rootStream << id;
   398 	rootStream.CommitL();
   399 	CleanupStack::PopAndDestroy(&rootStream);
   400 
   401 	store->SetRootL(rootId);
   402 	store->CommitL();
   403 
   404 	CleanupStack::PopAndDestroy(store);
   405 	CleanupStack::Pop(); // deleteStoreFile
   406 	}
   407 
   408 void CFSCertAppsServer::RevertStore(TAny* aStore)
   409 	{
   410 	// this is a CleanupItem
   411 	__ASSERT_DEBUG(aStore, PanicServer(EPanicNotInitialised));
   412 
   413 	CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore *>(aStore);
   414 	store->Revert();
   415 	}
   416 
   417 void CFSCertAppsServer::DeleteStoreFile(TAny *aThis)
   418 	{
   419 	__ASSERT_DEBUG(aThis, PanicServer(EPanicNotInitialised));
   420 
   421 	// should call non-static member
   422 	
   423 	CFSCertAppsServer* self = reinterpret_cast<CFSCertAppsServer*>(aThis);
   424 
   425 	// Something strange has occurred if we can't get the ramStorePath.
   426 	// Since we can't leave we have to ignore the error
   427 	TFileName ramStorePath;
   428 	TRAPD(err, FileUtils::MakePrivateFilenameL(self->iFs, KCertAppsFilename, ramStorePath));
   429 	if (!err)
   430 		{
   431 		self->iFs.Delete(ramStorePath);
   432 		}
   433 	}
   434 
   435 void CFSCertAppsServer::ReplaceAndCommitL(TInt aExcludedIndex)
   436 	{
   437 	TCleanupItem cleanupStore(RevertStore, iStore);
   438 	CleanupStack::PushL(cleanupStore);
   439 
   440 	// compact the store 
   441 	iStore->ReclaimL(); // do we need to reclaim
   442 	iStore->CompactL();
   443 
   444 	RStoreWriteStream outputStream;
   445 	outputStream.ReplaceLC(*iStore, iId);
   446 
   447 	WriteClientArrayL(outputStream, aExcludedIndex);
   448 
   449 	CleanupStack::PopAndDestroy(&outputStream);
   450 	iStore->CommitL();
   451 	CleanupStack::Pop(); // cleanupStore
   452 	}
   453 
   454 void CFSCertAppsServer::WriteClientArrayL(RWriteStream& stream, TInt aExcludedIndex) const
   455 	{
   456 	// the count of elements to be written is the arraycount - 1 if we exclude 
   457 	// something, otherwise the arraycount
   458 	TInt arrayEnd = iClients.Count();
   459 	TInt count = (aExcludedIndex < 0) ? (arrayEnd) : (arrayEnd - 1);
   460 
   461 	stream.WriteInt32L(count);
   462 
   463 	for (TInt i = 0; i < arrayEnd; ++i)
   464 		{
   465 		if (i != aExcludedIndex)
   466 			{
   467 			stream << iClients[i];	// This can leave
   468 			}
   469 		}
   470 	stream.CommitL();
   471 	}