cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp
changeset 0 2c201484c85f
child 8 35751d3474b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp	Wed Jul 08 11:25:26 2009 +0100
@@ -0,0 +1,469 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: 
+*
+*/
+
+
+#include "CFSCertAppsServer.h"
+#include "CCertAppsSession.h"
+#include "CCertAppsConduit.h"
+#include "fstokencliserv.h"
+#include "fstokenutil.h"
+#include "certstorepatchdata.h"
+#include <certificateapps.h>
+#include <u32hal.h> 
+
+// Filename where all data is stored
+_LIT(KCertAppsFilename,"certclients.dat");
+_LIT(KCertAppsFile,"certclients*.dat");
+
+CFSCertAppsServer* CFSCertAppsServer::NewL()
+	{
+	CFSCertAppsServer* self = new (ELeave) CFSCertAppsServer();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CFSCertAppsServer::CFSCertAppsServer()
+	{
+	}
+
+void CFSCertAppsServer::ConstructL()
+	{
+	iConduit = CCertAppsConduit::NewL(*this);
+	
+	// Connect to the filesystem
+	User::LeaveIfError(iFs.Connect());
+
+	iPatchableConst = KAggregateCertStore;
+	
+	#ifdef __WINS__
+		// For the emulator allow the constant to be patched via epoc.ini
+		UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
+		(TAny*)"KAggregateCertStore", &iPatchableConst); // read emulator property (if present)
+	#endif		
+	
+	// Retrieves the store
+	OpenStoreL();
+	}
+
+CFSCertAppsServer::~CFSCertAppsServer()
+	{
+	delete iStore;
+ 	iFs.Close();
+	iClients.Close();
+	delete iConduit;
+	}
+
+CCertAppsSession* CFSCertAppsServer::CreateSessionL()
+	{
+	return CCertAppsSession::NewL(*iConduit); 
+	}
+
+void CFSCertAppsServer::AddL(const TCertificateAppInfo& aClient)
+	{
+	// see if application already exists. If so, then leave
+	
+	if (FindApplication(aClient.Id()))
+		{
+		User::Leave(KErrAlreadyExists);
+		}
+	User::LeaveIfError(iClients.Append(aClient));
+	TRAPD(err, ReplaceAndCommitL(-1));
+	if (err != KErrNone)
+		{
+		// We must remove the client from iClients if we didn't manage 
+		// to add it to the store
+		iClients.Remove(iClients.Count() - 1);
+		User::Leave(err);
+		}
+	}
+
+void CFSCertAppsServer::RemoveL(const TUid& aUid)
+	{
+	// Make sure the application for that uid exists
+	TInt i;
+	if (!FindApplication(aUid, &i))
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	ReplaceAndCommitL(i);
+	
+	// We managed to remove it from the store, so we remove it from the
+	// iClients array
+	iClients.Remove(i);
+	}
+
+TInt CFSCertAppsServer::ApplicationCountL() const
+	{
+	return iClients.Count();
+	}
+
+void CFSCertAppsServer::ApplicationsL(RArray<TCertificateAppInfo>& aAppArray) const
+	{
+	// Make a copy of the array
+	TInt count = iClients.Count();
+
+	for (TInt i = 0; i < count; ++i)
+		{
+		aAppArray.Append(iClients[i]);
+		}
+	}
+
+void CFSCertAppsServer::ApplicationL(const TUid& aUid, TCertificateAppInfo& aInfo) const
+	{
+	const TCertificateAppInfo* app = FindApplication(aUid);
+
+	// leave if not found
+	if (!app)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	// make a copy and return to client
+	aInfo = *app;
+	}
+
+const TCertificateAppInfo* CFSCertAppsServer::FindApplication(const TUid& aUid, TInt* aIndex) const
+	{
+	// This helper function tries to find an application with the given
+	// Uid. It returns NULL if not found. aIndex returns the index into
+	// the array successful
+	const TCertificateAppInfo* retVal = NULL;
+	TInt end = iClients.Count();
+	for (TInt i = 0; i < end; ++i)
+		{
+		if (iClients[i].Id() == aUid)
+			{
+			// check if an index is required to be returned
+			if (aIndex)
+				{
+				*aIndex = i;
+				}
+			retVal = &iClients[i];
+			break;
+			}
+		}
+
+	return retVal;
+	}
+
+void CFSCertAppsServer::AggregateStoreFileL(const TDesC& aFile)
+	{
+	ASSERT(iPatchableConst);
+
+	// if patchable constant is enabled
+	// 1. open read-only permanent file store on each file.
+	// 2. open certificate client entry list of each store.
+	// 3. aggregate the entries.
+	RFile file;
+	User::LeaveIfError(file.Open(iFs, aFile, EFileRead));
+	CleanupClosePushL(file);
+	CPermanentFileStore* store = CPermanentFileStore::FromL(file);
+	// now owned by store
+	CleanupStack::Pop(&file); 
+	CleanupStack::PushL(store);
+
+	// Read id of cert list stream
+	TStreamId streamId;
+	RStoreReadStream stream;
+	stream.OpenLC(*store, store->Root());
+	stream >> streamId;
+	CleanupStack::PopAndDestroy(&stream);
+	
+	// Read the certificate's clients entry list
+	stream.OpenLC(*store, streamId);
+	TInt count = stream.ReadInt32L();
+	RArray<TCertificateAppInfo> entryList;
+	for (TInt i = 0 ; i < count ; i++)
+		{
+		TCertificateAppInfo clientInfo;
+		stream >> clientInfo;
+		entryList.AppendL(clientInfo);
+		}
+	CleanupStack::PopAndDestroy(&stream);
+	CleanupClosePushL(entryList);
+
+	MergeCertificateEntryListL(entryList);
+	// cleanup entryList and store instances.
+	CleanupStack::PopAndDestroy(2,store);		
+	}
+
+TBool CFSCertAppsServer::FindUid(const TUid& aUid)
+	{
+	TInt end = iClients.Count();
+	for (TInt i = 0; i < end; ++i)
+		{
+		if (iClients[i].Id() == aUid)
+			{
+			return ETrue;
+			}
+		}
+	return EFalse;
+	}
+
+void CFSCertAppsServer::MergeCertificateEntryListL(const RArray<TCertificateAppInfo>& aSourceList)
+	{
+	ASSERT(iPatchableConst);
+
+	// if patchable constant is enabled
+	TInt sourceCount = aSourceList.Count();
+	for(TInt i = 0; i < sourceCount; i++)
+		{
+		// compare if the uid pre-exists in the composite list.
+		if (!FindUid(aSourceList[i].Id()))
+			{
+			// Aggregation: append this entry to the composite list.
+			iClients.AppendL(aSourceList[i]);
+			}
+		// Eclipsing: Higher order store cert client entries with same UIDs take precedence over lower order  
+		// store cert client entries therefore the later are not included in the composite cert client entry list.
+		// Higher order store client entries are ones which are aggregated prior to other client entries. 
+		}
+	}
+
+void CFSCertAppsServer::OpenCompositeStoreL(const TDesC& aFilename)
+	{
+	ASSERT(iPatchableConst);
+
+	// 1. create a new empty certstore file under system drive with the name 'certclients.dat'. 
+	// 2. this will be the composite store and the instances 'iEntryList' and 'iStore' will be initialized with this.
+	// 3. make private rom drive path where certstore files are located.
+	// 4. collect the certstore file names in a list.
+	// 5. make private rom drive path on each file.
+	// 6. populate the composite store with certificate client entries present in rom drive certstores.
+	
+	// create a new empty certstore file 'certclients.dat' under system drive.
+	CreateStoreL(aFilename);	
+	// restore permanent store on it 
+	// this will be the composite store after complete aggregation. 
+	ReadStoreContentsL(aFilename);
+		
+	RBuf romFilename;
+	romFilename.CreateL(KMaxFilenameLength);
+	CleanupClosePushL(romFilename);
+	FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFile, romFilename);
+	CDir* filenameList = NULL;
+	User::LeaveIfError(iFs.GetDir(romFilename, KEntryAttNormal, ESortByName|EDescending, filenameList));
+	CleanupStack::PopAndDestroy(&romFilename);
+	CleanupStack::PushL(filenameList);
+	TInt count = filenameList->Count();
+	
+	// aggregate ROM stores iteratively 
+	for(TInt index = 0; index < count; index++)		
+		{
+		RBuf fileName;
+		fileName.CreateL(KMaxFileName);
+		CleanupClosePushL(fileName);	
+		FileUtils::MakePrivateROMFilenameL(iFs, ((*filenameList)[index]).iName, fileName);
+		// if there is any corrupt certstore present then we will simply ignore its
+		// aggregation and proceed with aggregating remaining stores.
+		TRAP_IGNORE(AggregateStoreFileL(fileName));
+		CleanupStack::PopAndDestroy(&fileName);	
+		}
+	// write the 'iClients' to the composite store.	
+	ReplaceAndCommitL(-1);	
+	CleanupStack::PopAndDestroy(filenameList);
+	}
+
+// this logic should be handled by a superclass or mixin
+void CFSCertAppsServer::OpenStoreL()
+	{
+	RBuf filename;
+	filename.CreateL(KMaxFilenameLength);
+	CleanupClosePushL(filename);		
+	FileUtils::MakePrivateFilenameL(iFs, KCertAppsFilename, filename);
+
+	// Attempt to open the store
+	// need to test opening corrupt store
+	TRAPD(err, ReadStoreContentsL(filename));
+
+	if (err == KErrNoMemory || err == KErrInUse)
+		{
+		User::Leave(err);
+		}
+	
+	if (err != KErrNone)
+		{
+		// Couldn't open RAM based store, copy from ROM	
+		FileUtils::EnsurePathL(iFs, filename);		
+	
+		if(iPatchableConst)
+			{
+			OpenCompositeStoreL(filename);
+			}
+		else
+			{
+			RBuf romFilename;
+			romFilename.CreateL(KMaxFilenameLength);
+			CleanupClosePushL(romFilename);			
+			FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFilename, romFilename);
+			
+			if (FileUtils::ExistsL(iFs, romFilename))
+				{
+				FileUtils::CopyL(iFs, romFilename, filename);
+				}
+			else
+				{
+				CreateStoreL(filename);
+				}
+			CleanupStack::PopAndDestroy(&romFilename);
+			//Retry open, and leave on failure
+			ReadStoreContentsL(filename);			
+			}
+		}
+	CleanupStack::PopAndDestroy(&filename);
+	ASSERT(iStore);
+	}
+
+void CFSCertAppsServer::ReadStoreContentsL(const TDesC& aFilename)
+	{
+	// Make sure the store is not read-only
+	User::LeaveIfError(iFs.SetAtt(aFilename, KEntryAttNormal, KEntryAttReadOnly));
+
+	RFile file;
+	User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileWrite));
+	CleanupClosePushL(file);
+	CPermanentFileStore* store = CPermanentFileStore::FromL(file);
+	CleanupStack::Pop(&file);
+	CleanupStack::PushL(store);
+
+	// now read the root stream to get the id of our main stream
+	RStoreReadStream readStream;
+	readStream.OpenLC(*store, store->Root());
+	readStream >> iId;	// This can leave
+	CleanupStack::PopAndDestroy(&readStream);
+
+	// finally, restore the stream which contains the client arrays.
+	// First long is the number of entries, then each entry 
+	readStream.OpenLC(*store, iId);
+	TInt count = readStream.ReadInt32L();
+	for (TInt i = 0; i < count; ++i)
+		{
+		TCertificateAppInfo clientInfo;
+		readStream >> clientInfo;
+		User::LeaveIfError(iClients.Append(clientInfo));
+		}
+	CleanupStack::PopAndDestroy(&readStream);
+
+	ASSERT(!iStore);
+	iStore = store;
+	CleanupStack::Pop(store);
+	}
+
+void CFSCertAppsServer::CreateStoreL(const TDesC& aFilename)
+	{
+	// If for some reason we can't complete the creation of the store, we want
+	// to be sure that we don't leave a half-constructed store on the device
+	// as we will then be in trouble when we try to open the store
+	TCleanupItem deleteStoreFile(DeleteStoreFile, this);
+	CleanupStack::PushL(deleteStoreFile);
+
+	iFs.Delete(aFilename); // ignore errors
+
+	RFile file;
+	User::LeaveIfError(file.Create(iFs, aFilename, EFileWrite));
+	CleanupClosePushL(file);
+	
+	CPermanentFileStore* store = CPermanentFileStore::NewL(file);
+	CleanupStack::Pop(&file); // now owned by store
+	CleanupStack::PushL(store);
+	store->SetTypeL(KPermanentFileStoreLayoutUid);
+
+	RStoreWriteStream clientsStream;
+	TStreamId id = clientsStream.CreateLC(*store);
+	WriteClientArrayL(clientsStream);
+	CleanupStack::PopAndDestroy(&clientsStream);
+
+	RStoreWriteStream rootStream;
+	TStreamId rootId = rootStream.CreateLC(*store);
+	rootStream << id;
+	rootStream.CommitL();
+	CleanupStack::PopAndDestroy(&rootStream);
+
+	store->SetRootL(rootId);
+	store->CommitL();
+
+	CleanupStack::PopAndDestroy(store);
+	CleanupStack::Pop(); // deleteStoreFile
+	}
+
+void CFSCertAppsServer::RevertStore(TAny* aStore)
+	{
+	// this is a CleanupItem
+	__ASSERT_DEBUG(aStore, PanicServer(EPanicNotInitialised));
+
+	CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore *>(aStore);
+	store->Revert();
+	}
+
+void CFSCertAppsServer::DeleteStoreFile(TAny *aThis)
+	{
+	__ASSERT_DEBUG(aThis, PanicServer(EPanicNotInitialised));
+
+	// should call non-static member
+	
+	CFSCertAppsServer* self = reinterpret_cast<CFSCertAppsServer*>(aThis);
+
+	// Something strange has occurred if we can't get the ramStorePath.
+	// Since we can't leave we have to ignore the error
+	TFileName ramStorePath;
+	TRAPD(err, FileUtils::MakePrivateFilenameL(self->iFs, KCertAppsFilename, ramStorePath));
+	if (!err)
+		{
+		self->iFs.Delete(ramStorePath);
+		}
+	}
+
+void CFSCertAppsServer::ReplaceAndCommitL(TInt aExcludedIndex)
+	{
+	TCleanupItem cleanupStore(RevertStore, iStore);
+	CleanupStack::PushL(cleanupStore);
+
+	// compact the store 
+	iStore->ReclaimL(); // do we need to reclaim
+	iStore->CompactL();
+
+	RStoreWriteStream outputStream;
+	outputStream.ReplaceLC(*iStore, iId);
+
+	WriteClientArrayL(outputStream, aExcludedIndex);
+
+	CleanupStack::PopAndDestroy(&outputStream);
+	iStore->CommitL();
+	CleanupStack::Pop(); // cleanupStore
+	}
+
+void CFSCertAppsServer::WriteClientArrayL(RWriteStream& stream, TInt aExcludedIndex) const
+	{
+	// the count of elements to be written is the arraycount - 1 if we exclude 
+	// something, otherwise the arraycount
+	TInt arrayEnd = iClients.Count();
+	TInt count = (aExcludedIndex < 0) ? (arrayEnd) : (arrayEnd - 1);
+
+	stream.WriteInt32L(count);
+
+	for (TInt i = 0; i < arrayEnd; ++i)
+		{
+		if (i != aExcludedIndex)
+			{
+			stream << iClients[i];	// This can leave
+			}
+		}
+	stream.CommitL();
+	}