pkiutilities/DeviceToken/Src/Certstore/server/DevandTruSrvCertStoreServer.cpp
changeset 0 164170e6151a
child 16 9971b621ef6c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkiutilities/DeviceToken/Src/Certstore/server/DevandTruSrvCertStoreServer.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,684 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:   Implementation of DevandTruSrvCertStoreServer
+*
+*/
+
+
+#include <ccertattributefilter.h>
+#include <signed.h>
+#include <x509cert.h>
+#include <x509certext.h>
+#include <x509keys.h>
+#include <wtlscert.h>
+#include <x500dn.h>
+#include "DevandTruSrvCertStoreServer.h"
+#include "DevandTruSrvCertStoreConduit.h"
+#include "DevandTruSrvCertStoreSession.h"
+#include "DevandTruSrvCertStoreEntry.h"
+#include "DevandTruSrvCertStoreEntryList.h"
+#include "DevTokenCliServ.h"
+#include "DevTokenUtil.h"
+#include "DevTokenDataTypes.h"
+#include "TrustedSitesServer.h"
+
+_LIT(KCertStoreFilename,"devandtrusrvcerts.dat");
+
+const TInt KSHA1Length = 20;
+
+// API policing 
+_LIT_SECURITY_POLICY_PASS(KPolicyAlwaysPass);
+_LIT_SECURITY_POLICY_FAIL(KPolicyAlwaysFail);
+_LIT_SECURITY_POLICY_C1(KPolicyRequireReadUserData, ECapabilityReadUserData);
+_LIT_SECURITY_POLICY_C1(KPolicyRequireWriteDeviceData, ECapabilityWriteDeviceData);
+
+// ======== MEMBER FUNCTIONS ========
+
+//CDevandTruSrvCertStoreServer
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::NewL()
+// ---------------------------------------------------------------------------
+//
+CDevandTruSrvCertStoreServer* CDevandTruSrvCertStoreServer::NewL(CTrustedSitesServer* aTrustedSitesServer )
+    {
+    CDevandTruSrvCertStoreServer* self = new (ELeave) CDevandTruSrvCertStoreServer( aTrustedSitesServer );
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::CDevandTruSrvCertStoreServer()
+// ---------------------------------------------------------------------------
+//
+CDevandTruSrvCertStoreServer::CDevandTruSrvCertStoreServer( CTrustedSitesServer* aTrustedSitesServer )
+: iTrustedSitesServer( aTrustedSitesServer )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::ConstructL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::ConstructL()
+    {
+    iConduit = CDevandTruSrvCertStoreConduit::NewL(*this);
+    User::LeaveIfError(iFs.Connect());
+    OpenStoreL();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::~CDevandTruSrvCertStoreServer()
+// ---------------------------------------------------------------------------
+//
+CDevandTruSrvCertStoreServer::~CDevandTruSrvCertStoreServer()
+    {
+    delete iStore;
+    delete iEntryList;
+    delete iConduit;
+    iFs.Close();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::CreateSessionL()
+// ---------------------------------------------------------------------------
+//
+CDevandTruSrvCertStoreSession* CDevandTruSrvCertStoreServer::CreateSessionL()
+    {
+    return CDevandTruSrvCertStoreSession::NewL(*iConduit);
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::ListPolicy()
+// ---------------------------------------------------------------------------
+//
+const TSecurityPolicy& CDevandTruSrvCertStoreServer::ListPolicy(TCertificateOwnerType aOwnerType) const
+    {
+    switch (aOwnerType)
+        {
+        case EUserCertificate:
+            return KPolicyAlwaysPass;
+        case EPeerCertificate:
+            return KPolicyRequireReadUserData;
+
+        default:
+            return KPolicyAlwaysFail;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::AddRemovePolicy()
+// ---------------------------------------------------------------------------
+//
+const TSecurityPolicy& CDevandTruSrvCertStoreServer::AddRemovePolicy(TCertificateOwnerType aOwnerType) const
+    {
+    switch (aOwnerType)
+        {
+        case EUserCertificate:
+        case EPeerCertificate:
+            return KPolicyRequireWriteDeviceData;
+
+        default:
+            return KPolicyAlwaysFail;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::RetrievePolicy()
+// ---------------------------------------------------------------------------
+//
+const TSecurityPolicy& CDevandTruSrvCertStoreServer::RetrievePolicy(TCertificateOwnerType aOwnerType) const
+    {
+    switch (aOwnerType)
+        {
+        case EUserCertificate:
+        case EPeerCertificate:
+            return KPolicyRequireReadUserData;
+
+        default:
+            return KPolicyAlwaysFail;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::WriteTrustSettingsPolicy()
+// ---------------------------------------------------------------------------
+//
+const TSecurityPolicy& CDevandTruSrvCertStoreServer::WriteTrustSettingsPolicy() const
+    {
+    return KPolicyRequireWriteDeviceData;
+    }
+
+
+// Read-only interface 
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::ListL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::ListL(const CCertAttributeFilter& aFilter,
+                 RPointerArray<CDevTokenCertInfo>& aCertsOut,
+                 const RMessage2& aMessage, TBool aFromTruSiteSrv ) const
+    {
+
+    // check that if KeyUsage is set, only User certificates are requested
+    if (aFilter.iKeyUsage != EX509UsageAll &&
+    (!aFilter.iOwnerTypeIsSet || aFilter.iOwnerType != EUserCertificate))
+        {
+        User::Leave(KErrArgument);
+        }
+
+    // API policing
+    if (!aFromTruSiteSrv)
+        {
+        if (!ListPolicy( aFilter.iOwnerType ).CheckPolicy(aMessage))
+            {
+            User::Leave(KErrPermissionDenied);
+            } 	
+        } 
+
+    TInt count = iEntryList->Count();
+    for (TInt index = 0; index < count; index++)
+        {
+        const CDevandTruSrvCertStoreEntry& entry = iEntryList->GetByIndex(index);
+
+        if (CertEntryMatchesFilter(aFilter, entry))
+            {
+            User::LeaveIfError(aCertsOut.Append(&entry.CertInfo()));
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::CertEntryMatchesFilter()
+// ---------------------------------------------------------------------------
+//
+TBool CDevandTruSrvCertStoreServer::CertEntryMatchesFilter(const CCertAttributeFilter& aFilter,
+                         const CDevandTruSrvCertStoreEntry& aEntry) const
+    {
+    if (aFilter.iUidIsSet && !aEntry.IsApplicable(aFilter.iUid))
+        {
+        return EFalse;
+        }
+
+    const CDevTokenCertInfo& certInfo = aEntry.CertInfo();
+
+    if (aFilter.iFormatIsSet && aFilter.iFormat != certInfo.CertificateFormat())
+        {
+        return EFalse;
+        }
+
+    if (aFilter.iOwnerTypeIsSet && aFilter.iOwnerType != certInfo.CertificateOwnerType())
+        {
+        return EFalse;
+        }
+
+    if (aFilter.iSubjectKeyIdIsSet && aFilter.iSubjectKeyId != certInfo.SubjectKeyId())
+        {
+        return EFalse;
+        }
+
+    if (aFilter.iLabelIsSet && aFilter.iLabel != certInfo.Label())
+        {
+        return EFalse;
+        }
+
+    return ETrue;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::GetCertL()
+// ---------------------------------------------------------------------------
+//
+const CDevTokenCertInfo& CDevandTruSrvCertStoreServer::GetCertL(TInt aHandle) const 
+    {
+    // Leaves if not found
+    return iEntryList->GetByHandleL(aHandle).CertInfo();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::ApplicationsL()
+// ---------------------------------------------------------------------------
+//
+const RArray<TUid>& CDevandTruSrvCertStoreServer::ApplicationsL(TInt aHandle) const
+    {
+    return iEntryList->GetByHandleL(aHandle).CertificateApps();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::IsApplicableL()
+// ---------------------------------------------------------------------------
+//
+TBool CDevandTruSrvCertStoreServer::IsApplicableL(TInt aHandle, TUid aApplication) const
+    {
+    return iEntryList->GetByHandleL(aHandle).IsApplicable(aApplication);
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::TrustedL()
+// ---------------------------------------------------------------------------
+//
+TBool CDevandTruSrvCertStoreServer::TrustedL(TInt aHandle) const
+    { 
+    return iEntryList->GetByHandleL(aHandle).Trusted();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::RetrieveLC()
+// ---------------------------------------------------------------------------
+//
+HBufC8* CDevandTruSrvCertStoreServer::RetrieveLC(TInt aHandle, const RMessage2& aMessage, TBool aFromTruSiteSrv) const
+    {
+    const CDevandTruSrvCertStoreEntry& entry = iEntryList->GetByHandleL(aHandle);
+
+    // API policing
+    if ( !aFromTruSiteSrv )
+        {
+        if (!RetrievePolicy(entry.CertInfo().CertificateOwnerType()).CheckPolicy(aMessage))
+            {
+            User::Leave( KErrPermissionDenied );
+            }	
+        }
+
+    TInt size = entry.CertInfo().Size();
+    HBufC8* buf = HBufC8::NewMaxLC(size);
+    TPtr8 ptr = buf->Des();
+    ptr.FillZ();
+
+    RStoreReadStream stream;
+    stream.OpenLC(*iStore, entry.DataStreamId());
+    stream.ReadL(ptr, size);
+    CleanupStack::PopAndDestroy(&stream);
+
+    return buf;
+    }
+
+
+// Writable interface
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::AddL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::AddL(const TDevTokenAddCertDataStruct& aInfo,
+                const TDesC8& aCert,
+                const RMessage2& aMessage, TBool aFromTruSiteSrv )
+    {
+    // Check if a certificate with this name already exists
+    if (iEntryList->LabelExists(aInfo.iLabel))
+        {
+        User::Leave(KErrBadName);
+        }
+
+    // Check subject key id and cert data are supplied, issuer key id is optional
+    if (aInfo.iSubjectKeyId == KNullDesC8 || aCert == KNullDesC8)
+        {
+        User::Leave(KErrArgument);
+        }
+
+    // Create cert entry (this sanity checks the rest of the arguments)
+    CDevTokenCertInfo* certInfo = CDevTokenCertInfo::NewLC(
+        aInfo.iLabel,
+        aInfo.iFormat, 
+        aInfo.iCertificateOwnerType,
+        aCert.Length(),
+        &aInfo.iSubjectKeyId,
+        &aInfo.iIssuerKeyId,
+        iEntryList->NextFreeHandle(),
+        aInfo.iDeletable);
+
+    // API policing
+    if ( !aFromTruSiteSrv )
+        {
+        if (!AddRemovePolicy(aInfo.iCertificateOwnerType).CheckPolicy(aMessage))
+            {
+            User::Leave(KErrPermissionDenied);
+            }	
+        }
+
+    CompactStoreL();
+
+    TRAPD(err, DoAddL(*certInfo, aCert));
+    CleanupStack::PopAndDestroy(certInfo);
+
+    if (err != KErrNone)
+        {
+        iStore->Revert();
+        User::Leave(err);
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::DoAddL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::DoAddL(const CDevTokenCertInfo& aCertInfo, const TDesC8& aCertData)
+    {
+    TStreamId dataStreamId = WriteCertDataStreamL(aCertData);
+
+    RArray<TUid> initialApps;
+    CleanupClosePushL(initialApps);
+
+    CDevandTruSrvCertStoreEntry* entry = CDevandTruSrvCertStoreEntry::NewL(
+        aCertInfo,
+        initialApps,
+        EFalse,
+        dataStreamId);
+    CleanupStack::PopAndDestroy(&initialApps);
+    CleanupStack::PushL(entry);
+
+    TInt index = iEntryList->AppendL(entry);
+    CleanupStack::Pop(entry); // iEntryList has taken ownership
+
+    TRAPD(err, UpdateStoreL());
+    if ( (err == KErrNone) && (aCertInfo.CertificateOwnerType() == EPeerCertificate ))
+        {
+        CX509Certificate* cert = CX509Certificate::NewLC( aCertData );
+        TBuf8<KSHA1Length> certHash;
+        certHash.Copy(cert->Fingerprint()); 
+         
+          
+        const CX500DistinguishedName& dName = cert->SubjectName();
+        // Retrieve CN
+        HBufC* cn = dName.ExtractFieldL( KX520CommonName );  
+        CleanupStack::PushL(cn);  
+        iTrustedSitesServer->AddL( certHash, *cn );
+
+        CleanupStack::PopAndDestroy( 2 );//cert, cn	
+        }
+    if (err != KErrNone)
+        {
+        iEntryList->Remove(index);
+        delete entry;
+        User::Leave(err);
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::WriteCertDataStreamL()
+// ---------------------------------------------------------------------------
+//
+TStreamId CDevandTruSrvCertStoreServer::WriteCertDataStreamL(const TDesC8& aData)
+    {
+    RStoreWriteStream stream;
+    TStreamId streamId = stream.CreateLC(*iStore);
+    stream.WriteL(aData);
+    stream.CommitL();
+    CleanupStack::PopAndDestroy(&stream);
+    return streamId;
+    } 
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::RemoveL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::RemoveL(TInt aHandle, const RMessage2& aMessage,  TBool aFromTruSiteSrv)
+    {
+    TInt index = iEntryList->IndexForHandle(aHandle);
+    User::LeaveIfError(index);
+
+    // API policing
+    const CDevandTruSrvCertStoreEntry& entry = iEntryList->GetByIndex(index);
+    if (!aFromTruSiteSrv)
+        {
+        if (!AddRemovePolicy(entry.CertInfo().CertificateOwnerType()).CheckPolicy(aMessage))
+            {
+            User::Leave(KErrPermissionDenied);
+            }	
+        }
+
+    CompactStoreL();
+
+    CDevandTruSrvCertStoreEntry* oldEntry = iEntryList->Remove(index);
+    TRAPD(err, UpdateStoreL());
+    if (err == KErrNone)
+        {
+        // If trusted site certificate is removed, the corresponding records
+        // in trusted site store should also be removed to stop trusting.
+        if( oldEntry->CertInfo().CertificateOwnerType() == EPeerCertificate )
+            {
+            TInt size = oldEntry->CertInfo().Size();
+            HBufC8* buf = HBufC8::NewMaxLC(size);
+            TPtr8 ptr = buf->Des();
+            ptr.FillZ();
+
+            RStoreReadStream stream;
+            stream.OpenLC(*iStore, oldEntry->DataStreamId());
+            stream.ReadL(ptr, size);
+            CleanupStack::PopAndDestroy(&stream);
+
+
+            CX509Certificate* cert = CX509Certificate::NewLC(*buf);
+            TBuf8<KSHA1Length> certHash;
+            certHash.Copy(cert->Fingerprint()); 
+
+            iTrustedSitesServer->RemoveL( certHash );
+
+            CleanupStack::PopAndDestroy( 2 );//buf, cert
+            }
+        delete oldEntry;
+        }
+    else
+        {
+        iStore->Revert();
+        // This will always succeed because we just did a remove
+        iEntryList->AppendL(oldEntry);
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::SetApplicabilityL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::SetApplicabilityL(TInt /*aHandle*/,
+                       const RArray<TUid>& /*aApps*/,
+                       const RMessage2& aMessage)
+    {
+    // Setting Applicability is meant for CA certificate only.
+    // in DevandTruSrvCertStore, we only store Personal ceritificate(Device Cert )
+    // and Peer certificate( trust server cert ).
+    
+    aMessage.Complete( KErrNotSupported ); 
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::SetTrustL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::SetTrustL(TInt /*aHandle*/,
+                   TBool /*aTrusted*/,
+                   const RMessage2& aMessage)
+    {
+    // Setting Trust is meant for CA certificate only.
+    // in DevandTruSrvCertStore, we only store Personal ceritificate(Device Cert )
+    // and Peer certificate( trust server cert ).
+    
+    aMessage.Complete( KErrNotSupported ); 
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::UpdateStoreL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::UpdateStoreL()
+    {
+    RStoreWriteStream stream;
+    stream.ReplaceLC(*iStore, iStreamId);
+    stream << *iEntryList;
+    stream.CommitL();
+    CleanupStack::PopAndDestroy(&stream);
+
+    iStore->CommitL();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::CompactStoreL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::CompactStoreL()
+    {
+    iStore->ReclaimL();
+    iStore->CompactL();
+    iStore->CommitL();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::RestoreL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::RestoreL(const TDesC& aFilename)
+    {
+    // Make sure the store is not read-only
+    User::LeaveIfError(iFs.SetAtt(aFilename, KEntryAttNormal, KEntryAttReadOnly));
+
+    // Open the store
+    RFile file;
+    User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileWrite));
+    CleanupClosePushL(file);
+    CPermanentFileStore* store = CPermanentFileStore::FromL(file);
+    CleanupStack::Pop(&file); // now owned by store
+    CleanupStack::PushL(store);
+
+    // Read id of cert list stream
+    TStreamId caCertEntryStreamId;
+    RStoreReadStream stream;
+    stream.OpenLC(*store, store->Root());
+    stream >> iStreamId;
+    CleanupStack::PopAndDestroy(&stream);
+
+    // Read the certificate list
+    RStoreReadStream caCertEntryStream;
+    caCertEntryStream.OpenLC(*store, iStreamId);
+    iEntryList = CDevandTruSrvCertStoreEntryList::NewL(caCertEntryStream);
+    CleanupStack::PopAndDestroy(&caCertEntryStream);
+
+    assert(!iStore, EPanicCertStoreRestoreState);
+    iStore = store;
+    CleanupStack::Pop(store);
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::OpenStoreL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::OpenStoreL()
+    {
+    TBuf<KMaxFilenameLength> filename;
+    FileUtils::MakePrivateFilenameL(iFs, KCertStoreFilename, filename);
+
+    TRAPD(err, RestoreL(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);
+
+        TBuf<KMaxFilenameLength> romFilename;
+        FileUtils::MakePrivateROMFilenameL(iFs, KCertStoreFilename, romFilename);
+
+        if (FileUtils::ExistsL(iFs, romFilename))
+            {
+            FileUtils::CopyL(iFs, romFilename, filename);
+            }
+        else
+            {
+            CreateStoreFileL(filename);
+            }
+
+        // Retry open, and leave on failure
+        RestoreL(filename);
+        }
+
+    assert(iStore, EPanicCertStoreOpenState);
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::CreateStoreFileL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::CreateStoreFileL(const TDesC& aFile)
+    {
+    TRAPD(err, DoCreateStoreFileL(aFile));
+    if (err != KErrNone)
+        {
+        // Attempt to delete file, but don't complain if it fails
+        iFs.Delete(aFile);  
+        User::Leave(err);
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDevandTruSrvCertStoreServer::DoCreateStoreFileL()
+// ---------------------------------------------------------------------------
+//
+void CDevandTruSrvCertStoreServer::DoCreateStoreFileL(const TDesC& aFile)
+    {
+    CPermanentFileStore* fileStore = CPermanentFileStore::ReplaceLC(iFs, aFile, EFileRead | EFileWrite | EFileShareExclusive);
+    fileStore->SetTypeL(KPermanentFileStoreLayoutUid);
+
+    // Create info stream
+    CDevandTruSrvCertStoreEntryList* emptyCertList = CDevandTruSrvCertStoreEntryList::NewLC();  
+    RStoreWriteStream infoStream;
+    TStreamId streamId = infoStream.CreateLC(*fileStore);
+    infoStream << *emptyCertList;
+    infoStream.CommitL();
+    CleanupStack::PopAndDestroy(2, emptyCertList);
+
+    // Create root stream - just contains id of info stream
+    RStoreWriteStream rootStream;
+    TStreamId rootStreamId = rootStream.CreateLC(*fileStore);
+    fileStore->SetRootL(rootStreamId);
+    rootStream << streamId;
+    rootStream.CommitL();
+    CleanupStack::PopAndDestroy(&rootStream);
+
+    fileStore->CommitL();
+    CleanupStack::PopAndDestroy(fileStore);
+    }
+
+//EOF
+