diff -r 000000000000 -r 2c201484c85f cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp --- /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 +#include + +// 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& 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 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& 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(aStore); + store->Revert(); + } + +void CFSCertAppsServer::DeleteStoreFile(TAny *aThis) + { + __ASSERT_DEBUG(aThis, PanicServer(EPanicNotInitialised)); + + // should call non-static member + + CFSCertAppsServer* self = reinterpret_cast(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(); + }