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