--- /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();
+ }