vpnengine/vpnmanager/src/policystore.cpp
changeset 0 33413c0669b9
child 20 352850cbed81
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/vpnmanager/src/policystore.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,1006 @@
+/*
+* Copyright (c) 2000-2007 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:   Policy store
+*
+*/
+
+
+
+#include <e32math.h>
+#include <cmconnectionmethod.h>
+#include <cmpluginvpndef.h> // vpn plugin
+#include "policystore.h"
+#include "pinparser.h"
+#include "ikepolparser.h"
+#include "pkiserviceapi.h"
+#include "policyimporter.h"
+#include "uuid.h"
+#include "log_r6.h"
+
+CPolicyStore* CPolicyStore::NewL(RFs& aFs)
+    {
+    CPolicyStore* self = new (ELeave) CPolicyStore(aFs);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(); // self
+    return self;
+    }
+
+CPolicyStore::CPolicyStore(RFs& aFs) : iFs(aFs), iFileUtil(aFs)
+    {
+    }
+
+inline void CPolicyStore::ConstructL()
+    {
+    LOG_("CPolicyStore::ConstructL");    
+    ConstructPolicyListL();
+    LOG_("CPolicyStore::ConstructL:end");    
+    }
+
+CPolicyStore::~CPolicyStore()
+    {
+    delete iPolicyListAll;
+    delete iPolicyListVisible;
+    }
+
+void CPolicyStore::ConstructPolicyListL()
+    {
+    // Using two policy lists (one for all and one for the visible
+    // ones) makes it easy to support the concept of hidden and
+    // visible policies. There's a slight memory penalty but this
+    // is not serious as the number of policies is typically small).
+    // Hidden policies differ from visible ones in only one aspect - 
+    // they are not included in the policy listing returned to
+    // the caller.
+    
+    // A list of all policies (both visible and hidden)
+    iPolicyListAll = new (ELeave) CArrayFixFlat<TVpnPolicyInfo>(2);
+    // A list of visible policies only
+    iPolicyListVisible = new (ELeave) CArrayFixFlat<TVpnPolicyInfo>(2);
+
+    TFindFile fileFinder(iFs);
+    CDir* fileList; 
+
+    TPath privateDir;
+    User::LeaveIfError(iFs.PrivatePath(privateDir));
+    TInt ret = fileFinder.FindWildByDir(KPolFilePat, privateDir, fileList);
+    if (ret == KErrNone)
+        {
+        CleanupStack::PushL(fileList);
+        
+        for (TInt i = 0; i < fileList->Count(); i++)
+            {
+            TParse fileNameParser;
+            fileNameParser.Set((*fileList)[i].iName, &fileFinder.File(), NULL);
+
+            TVpnPolicyId policyId;
+            
+            // Only add the policy to the list its ID length is
+            // acceptable (this is the case with all policies
+            // that have been properly imported to the store)
+            if (fileNameParser.Name().Length() <= policyId.MaxLength())
+                {
+                policyId.Copy(fileNameParser.Name());
+
+                HBufC* pinFile = iFileUtil.GetPinFileNameLC(policyId);
+
+                if (iFileUtil.FileExists(*pinFile))
+                    {
+                    AddPolicyL(policyId);
+                    }
+                CleanupStack::PopAndDestroy(pinFile);
+                }
+            }
+        
+        CleanupStack::PopAndDestroy(); // fileList
+        }
+    }
+
+TUint8* CPolicyStore::RawPolicyData()
+    {
+    // The list of policies returned to the caller contains ONLY
+    // visible policies. 
+    return reinterpret_cast<TUint8*>(&(iPolicyListVisible->At(0)));
+    }
+
+void CPolicyStore::ImportPolicyL(
+    const TFileName& aPinFile, const TFileName& aPolFile,
+    TVpnPolicyId* aNewPolicyId)
+    {
+    LOG_("-> CPolicyStore::ImportPolicyL()");            
+    TVpnPolicyId policyId = NewPolicyIdL();
+
+    // Write the new policy ID to the caller
+    if (aNewPolicyId)
+        {
+        aNewPolicyId->Copy(policyId);
+        }
+
+    // Create new PIN and POL file names
+    // (Dynamic allocation to conserve stack space)
+    HBufC* pinFileP = iFileUtil.GetPinFileNameLC(policyId);
+    HBufC* polFileP = iFileUtil.GetPolFileNameLC(policyId);
+
+    // Move the files from the install directory
+    // to the target directory (the policy store)
+    iFileUtil.CopyFileL(aPinFile, *pinFileP);
+    iFileUtil.CopyFileL(aPolFile, *polFileP);
+
+    CleanupStack::PopAndDestroy(polFileP);
+
+    // Make sure that the name of the new policy
+    // does not collide with an existing name
+    EnsureUniquePolicyNameL(*pinFileP);
+
+    CleanupStack::PopAndDestroy(pinFileP);
+    
+    // Add the imported policy to the policy list
+    AddPolicyL(policyId);
+    LOG(Log::Printf(_L("<- CPolicyStore::ImportPolicyL()")));            
+    }
+
+TInt CPolicyStore::DeletePolicyL(const TVpnPolicyId& aPolicyId)
+    {
+    LOG(Log::Printf(_L("-> CPolicyStore::DeletePolicyL()")));            
+    // Delete the policy from the list of all policies
+    
+    TInt itemToDelete = PolicyIndex(aPolicyId);
+    
+    if (itemToDelete != KUnfoundIndex)
+        {
+        iPolicyListAll->Delete(itemToDelete);
+        iPolicyListAll->Compress();
+        }
+
+    // Delete the policy also from the list of
+    // visible policies if it happens to be there
+    
+    TInt itemToDeleteVisible = PolicyIndexVisible(aPolicyId);
+    
+    if (itemToDeleteVisible != KUnfoundIndex)
+        {
+        iPolicyListVisible->Delete(itemToDeleteVisible);
+        iPolicyListVisible->Compress();
+        }
+
+    // Delete the PIN and POL files
+    HBufC* pinFile = iFileUtil.GetPinFileNameLC(aPolicyId);    
+    HBufC* polFile = iFileUtil.GetPolFileNameLC(aPolicyId);
+
+    if (iFileUtil.FileExists(*pinFile))
+        {
+        iFileUtil.DeleteFileL(*pinFile); 
+        }
+    
+    if (iFileUtil.FileExists(*polFile))
+        {
+        iFileUtil.DeleteFileL(*polFile);
+        }
+    CleanupStack::PopAndDestroy(2); // polFile, pinFile
+    LOG(Log::Printf(_L("<- CPolicyStore::DeletePolicyL()")));            
+    return KErrNone;
+    }
+    
+TInt CPolicyStore::PolicyCount()
+    {
+    // The list of policies returned to the caller contains ONLY
+    // visible policies. Thus we return just the count of those.
+    return iPolicyListVisible->Count();
+    }
+
+TInt CPolicyStore::GetPolicyInfo(const TVpnPolicyId& aPolicyId, TVpnPolicyInfo& aPolicyInfo)
+    {
+    TInt policyIndex = PolicyIndex(aPolicyId);
+    
+    if (policyIndex == KUnfoundIndex)
+        {
+        return KVpnErrPolicyNotFound;
+        }
+    else
+        {
+        aPolicyInfo = iPolicyListAll->At(policyIndex);
+        return KErrNone;
+        }
+    }
+
+TInt CPolicyStore::GetPolicyDetailsL(
+    const TVpnPolicyId& aPolicyId, 
+    TVpnPolicyDetails& aPolicyDetails)
+    {
+    LOG(Log::Printf(_L("-> CPolicyStore::GetPolicyDetailsL()")));            
+    TInt policyIndex = PolicyIndex(aPolicyId);
+    
+    if (policyIndex == KUnfoundIndex)
+        {
+        LOG(Log::Printf(_L("<- CPolicyStore::GetPolicyDetailsL() (KVpnErrPolicyNotFound)")));
+        return KVpnErrPolicyNotFound;
+        }
+    else
+        {
+        STACK_LEFT;
+        
+        // Get static policy information from the PIN file
+        TPinParser* pinParser = new (ELeave) TPinParser(iFileUtil);
+        CleanupStack::PushL(pinParser);
+
+        HBufC* pinFile = iFileUtil.GetPinFileNameLC(aPolicyId);
+        pinParser->ParsePolicyDetailsL(*pinFile, aPolicyDetails);
+
+        CleanupStack::PopAndDestroy(2); // pinFile, pinParser
+
+        // Find out dynamic policy information from the system
+        aPolicyDetails.iPkiStatus = PolicyPkiStatusL(aPolicyId);
+        aPolicyDetails.iUsageStatus = 
+            PolicyUsageStatusL(aPolicyId);
+        // Set the policy ID as well
+        aPolicyDetails.iId.Copy(aPolicyId);
+        
+        LOG(Log::Printf(_L("<- CPolicyStore::GetPolicyDetailsL()")));
+        return KErrNone;
+        }
+    }
+
+TInt CPolicyStore::LoadPolicyDataL(const TVpnPolicyId& aPolicyId, 
+    HBufC8*& aPolicyData)
+    {
+    TInt policyIndex = PolicyIndex(aPolicyId);
+    
+    if (policyIndex == KUnfoundIndex)
+        {
+        return KVpnErrPolicyNotFound;
+        }
+    HBufC* polFile = iFileUtil.GetPolFileNameLC(aPolicyId);
+    
+    aPolicyData = iFileUtil.LoadFileDataL(*polFile);
+
+    CleanupStack::PopAndDestroy();
+    return KErrNone;
+    }
+
+void CPolicyStore::AddPolicyL(const TVpnPolicyId& aPolicyId)
+    {
+    LOG(Log::Printf(_L("-> CPolicyStore::AddPolicyL")));    
+
+    TVpnPolicyInfo* policyInfo = new (ELeave) TVpnPolicyInfo();
+    CleanupStack::PushL(policyInfo);
+
+    policyInfo->iId = aPolicyId;
+    // Policy name is read from the PIN file
+    HBufC* pinFile = iFileUtil.GetPinFileNameLC(aPolicyId);
+
+    TPinParser* pinParser = new (ELeave) TPinParser(iFileUtil);
+    CleanupStack::PushL(pinParser);
+
+    pinParser->ParsePolicyInfoL(*pinFile, *policyInfo);
+    
+    CleanupStack::PopAndDestroy(pinParser);
+    CleanupStack::PopAndDestroy(pinFile);
+
+    LOG(Log::Printf(_L("pinParser.ParsePolicyInfoL completed")));
+    iPolicyListAll->AppendL(*policyInfo);
+
+    // A visible policy is added also
+    // to the list of visible policies
+    if (!IsHiddenPolicyL(policyInfo->iId))
+        {
+        iPolicyListVisible->AppendL(*policyInfo);
+        }
+
+    CleanupStack::PopAndDestroy(policyInfo);
+    LOG(Log::Printf(_L("<- CPolicyStore::AddPolicyL")));            
+    }
+
+TVpnPolicyId CPolicyStore::NewPolicyIdL()
+    {
+    TUuid uuid;
+    TUuidString uuidString;
+    
+    Uuid::MakeUuidL(uuid);
+
+    // It has become apparent that certain
+    // Symbian OS devices generate duplicate random
+    // number sequences after gold boot due to improper
+    // seeding of the random number generator. Should
+    // this happen to be the case, we insert at least
+    // one component to the UUID that depends on the 
+    // current system time. This is not perfect, but 
+    // should give us policy IDs that are unique enough.
+    TTime now;
+	now.UniversalTime();
+    TInt64 randSeed = now.Int64();
+    TInt randomNum = Math::Rand(randSeed);
+    uuid.iTimeLow = static_cast<TUint32>(randomNum);
+    
+    Uuid::UuidToString(uuid, uuidString);
+
+    TVpnPolicyId newPolicyId;
+    newPolicyId.Copy(uuidString);
+    
+    return newPolicyId;
+    }
+    
+TInt CPolicyStore::PolicyIndex(const TVpnPolicyId& aPolicyId)
+    {
+    for (TInt i = 0; i < iPolicyListAll->Count(); i++)
+        {
+        if (iPolicyListAll->At(i).iId.Compare(aPolicyId) == 0)
+            {
+            return i;
+            }
+        }
+    LOG_1("CPolicyStore::PolicyIndex not found:%S", &aPolicyId);
+    return KUnfoundIndex;
+    }
+
+TInt CPolicyStore::PolicyIndexVisible(const TVpnPolicyId& aPolicyId)
+    {
+    for (TInt i = 0; i < iPolicyListVisible->Count(); i++)
+        {
+        if (iPolicyListVisible->At(i).iId.Compare(aPolicyId) == 0)
+            {
+            return i;
+            }
+        }
+    return KUnfoundIndex;
+    }
+    
+TPolicyUsageStatus CPolicyStore::PolicyUsageStatusL(
+    const TVpnPolicyId& aPolicyId )
+    {
+    
+    LOG(Log::Printf(_L("-> CPolicyStore::PolicyUsageStatusL")));
+    
+    STACK_LEFT;
+    
+    TPolicyUsageStatus usageStatus = EUsageStatusUnused;
+
+using namespace CMManager;    
+    RCmManager cmManager;
+    cmManager.OpenL(); // Do not use LC it's not working yet
+    CleanupClosePushL( cmManager );
+    
+    TBool policyActive(EFalse);
+    if (PolicyAssignedToIapL(cmManager, aPolicyId, policyActive))
+        {
+        usageStatus = policyActive ? EUsageStatusActive : 
+            EUsageStatusAssignedToIap;
+        }
+    CleanupStack::PopAndDestroy(); // cmManager
+    
+    LOG(Log::Printf(_L("<- CPolicyStore::PolicyUsageStatusL")));
+    return usageStatus;
+    }
+
+TBool CPolicyStore::PolicyAssignedToIapL(
+    RCmManager& aCmManager,
+    const TVpnPolicyId& aPolicyId,
+    TBool& aPolicyActive)
+    {
+    STACK_LEFT;
+             
+    RArray<TUint32> vpnConnections;
+    ConnectionMethodsLC( 
+        vpnConnections, aCmManager, aPolicyId, aPolicyActive );
+    
+    TBool policyAssignedToIap( vpnConnections.Count() ? ETrue : EFalse );
+    CleanupStack::PopAndDestroy(); // vpnConnections
+    LOG_1("CPolicyStore::PolicyAssignedToIapL %d", policyAssignedToIap); 
+    return policyAssignedToIap;
+    }
+
+void CPolicyStore::ConnectionMethodsLC(
+    RArray<TUint32>& aVpnConnections,
+    RCmManager& aCmManager,
+    const TVpnPolicyId& aPolicyId,
+    TBool& aPolicyActive)
+    {
+using namespace CMManager;         
+    LOG_1("CPolicyStore::ConnectionMethodsLC : %S", &aPolicyId);
+    CleanupClosePushL( aVpnConnections );
+
+    aCmManager.ConnectionMethodL( 
+        aVpnConnections,
+        ETrue,
+        EFalse,
+        EFalse ); 
+    LOG_1("CPolicyStore::ConnectionMethodsLC cnt: %d", 
+        aVpnConnections.Count());
+    
+    TInt index(aVpnConnections.Count());
+    
+    while( index )
+        {
+        --index;
+        LOG_1("CPolicyStore::ConnectionMethodsLC at: %d", index);
+        TUint32 id(aVpnConnections[index]);
+        RCmConnectionMethod connectioMethod = 
+            aCmManager.ConnectionMethodL( id );
+        CleanupClosePushL( connectioMethod );  
+        if( connectioMethod.GetIntAttributeL(ECmBearerType) != 
+            KPluginVPNBearerTypeUid )
+            {
+            aVpnConnections.Remove( index );
+            }
+        else
+            {
+            HBufC* policyId = connectioMethod.GetStringAttributeL(
+                EVpnServicePolicy);
+            if( aPolicyId.Compare( *policyId ) )
+                {
+                aVpnConnections.Remove( index );
+                }
+            else
+                {
+                if( connectioMethod.GetBoolAttributeL(ECmConnected) )
+                    {
+                    LOG_1("PolicyActiveL:%d", index);
+                    aPolicyActive = ETrue;
+                    }
+                }
+            delete policyId;      
+            }
+        CleanupStack::PopAndDestroy(); // connectioMethod 
+        }
+    }
+
+TPolicyPkiStatus CPolicyStore::PolicyPkiStatusL(const TVpnPolicyId& aPolicyId)
+    {
+    HBufC8* policyData;
+    
+    if (LoadPolicyDataL(aPolicyId, policyData) != KErrNone)
+        {
+        return EPkiStatusUnknown;
+        }
+    
+    CleanupStack::PushL(policyData);
+
+    HBufC* policyData16 = HBufC::NewL(policyData->Length());
+    CleanupStack::PushL(policyData16);
+    
+    policyData16->Des().Copy(*policyData);
+
+    CIkeDataArray* ikeDataArray = CIkeDataArray::NewL(1);
+    CleanupStack::PushL(ikeDataArray);
+    
+    TIkeParser ikeParser(*policyData16);
+    ikeParser.ParseIKESectionsL(ikeDataArray);
+
+    // Go through each IKE section (VPN gateway definition)
+    // to find out the collective policy PKI status:
+    // - EPkiStatusReady if a valid user certificate is present for
+    // each VPN gateway defined in the policy
+    // - EPkiStatusNoCert if no user certificate is present for
+    // one or more VPN gateway defined in the policy
+    // - EPkiStatusCertExpired if a user certificate related
+    // to one or more VPN gateway has expired
+    // - EPkiStatusCertNotValidYet if a user certificate related
+    // to one or more VPN gateway is not yet valid
+    
+    TPolicyPkiStatus policyPkiStatus = EPkiStatusReady;
+    
+    for (TInt i = 0; i < ikeDataArray->Count(); i++)
+        {
+        CIkeData* ikeData = ikeDataArray->At(i);
+
+        TCertStatus gwPkiStatus = PolicyCertificateStatusL(ikeData);
+
+        // Determine the overall policy PKI status
+        
+        if (gwPkiStatus == ECertValid ||
+            gwPkiStatus == ECertNotNeeded)
+            {
+            continue;
+            }
+        else if (gwPkiStatus == ECertNotFound)
+            {
+            policyPkiStatus = EPkiStatusNoCert;
+            break;
+            }
+        else if (gwPkiStatus == ECertExpired)
+            {
+            policyPkiStatus = EPkiStatusCertExpired;
+            break;
+            }
+        else if (gwPkiStatus == ECertNotValidYet)
+            {
+            policyPkiStatus = EPkiStatusCertNotValidYet;
+            }
+        }
+
+    CleanupStack::PopAndDestroy(3); // ikeDataArray, policyData16, policyData
+    
+    return policyPkiStatus;
+    }
+         
+
+
+TCertStatus CPolicyStore::PolicyCertificateStatusL(CIkeData* aIkeData) const
+    {
+    LOG(Log::Printf(_L("-> CPolicyStore::PolicyCertificateStatusL()")));
+    TCertStatus status = ECertValid;
+
+    CArrayFixFlat<TCertInfo*> *cAList = aIkeData->iCAList;
+    if ((cAList == NULL || cAList->Count() == 0) && 
+        !aIkeData->iOwnCert.iOwnCertExists)
+        {
+        status = ECertNotNeeded;
+        }
+    else
+        {        
+        RPKIServiceAPI pkiService;
+        User::LeaveIfError(pkiService.Connect());
+        CleanupClosePushL(pkiService);
+
+        pkiService.SetInformational(ETrue);
+                    
+        CDesC8ArrayFlat* caSubjectNameArray = new (ELeave) CDesC8ArrayFlat(2);
+        CleanupStack::PushL(caSubjectNameArray);                        
+            
+        if (cAList != NULL && cAList->Count() > 0)
+            {                    
+            status = PkiUtil::GetValidCaCertSubjectNameListL(pkiService, *cAList,
+                                                             *caSubjectNameArray);        
+            }
+            
+        if (status == ECertValid)
+            {
+			// Set store type to device store,
+			// if Own_cert_type is defined as "DEVICE"            
+			if ( aIkeData->iClientCertType != NULL )
+			  	{
+				TPtrC16 certStoreType = aIkeData->iClientCertType->GetData();
+				if ( certStoreType.CompareF(_L("DEVICE")) == 0 )
+					{
+					LOG(Log::Printf(_L("Set store type to STORETYPE_DEVICE")));    
+					pkiService.SetStoreType(EPkiStoreTypeDevice);            
+					}
+                else
+                    {
+					LOG(Log::Printf(_L("Set store type to STORETYPE_USER")));    
+					pkiService.SetStoreType(EPkiStoreTypeUser);                                
+                    }
+				}
+            else
+                {
+				LOG(Log::Printf(_L("Set store type to STORETYPE_USER")));    
+				pkiService.SetStoreType(EPkiStoreTypeUser);                                                
+                }
+            status = PkiUtil::CheckUserCertValidityL(pkiService, *caSubjectNameArray,
+                                                     aIkeData->iOwnCert);
+            }
+        CleanupStack::PopAndDestroy(caSubjectNameArray);
+        CleanupStack::PopAndDestroy(); //pkiService            
+        }
+	LOG(Log::Printf(_L("<- CPolicyStore::PolicyCertificateStatusL()")));        
+    return status;
+    }
+
+
+
+void CPolicyStore::EnsureUniquePolicyNameL(const TFileName& aPinFile)
+    {
+    LOG_("-> CPolicyStore::EnsureUniquePolicyNameL");
+
+    // Dynamic allocations to conserve stack space
+
+    TVpnPolicyDetails* policyDetails = new (ELeave) TVpnPolicyDetails();
+    CleanupStack::PushL(policyDetails);
+
+    TPinParser* pinParserP = new (ELeave) TPinParser(iFileUtil);
+    CleanupStack::PushL(pinParserP);
+            
+    pinParserP->ParsePolicyDetailsL(aPinFile, *policyDetails);
+
+    TBool policyNameChanged = DoEnsureUniquePolicyNameL(*policyDetails);
+
+    if (policyNameChanged)
+        {
+        HBufC* pinFileContent = pinParserP->PolicyDetailsAsTextL(*policyDetails);
+        CleanupStack::PushL(pinFileContent);
+
+        iFileUtil.SaveFileDataL(aPinFile, *pinFileContent);
+
+        CleanupStack::PopAndDestroy(pinFileContent); // pinFileContent
+        }
+    CleanupStack::PopAndDestroy(); // pinParserP
+    CleanupStack::PopAndDestroy(); // policyDetails
+
+    LOG_("<- CPolicyStore::EnsureUniquePolicyNameL");
+    }
+
+TBool CPolicyStore::DoEnsureUniquePolicyNameL(TVpnPolicyDetails& aPolicyDetails)     
+    {
+    
+    LOG(Log::Printf(_L("-> CPolicyStore::DoEnsureUniquePolicyNameL")));    
+    TBool nameChanged = EFalse;
+    TBool isUnique = EFalse;
+    
+    HBufC* newName = aPolicyDetails.iName.AllocLC();
+    TInt sequenceNumber = 2;
+    
+    while (!isUnique && sequenceNumber < KMaxTInt)
+        {
+        if (PolicyNameExists(*newName))
+            {
+            if (newName != NULL) 
+                {
+                CleanupStack::PopAndDestroy(newName);
+                LOG_(" Pop (newName)");
+                newName = NULL;
+                }
+            newName = MakeNewPolicyNameL(aPolicyDetails.iName, sequenceNumber);
+            CleanupStack::PushL(newName);
+
+            sequenceNumber++;
+
+            nameChanged = ETrue;
+            }
+        else
+            {
+            isUnique = ETrue;
+            }
+        }
+
+    if (nameChanged)
+        {
+        // We now have a new unique policy name so we can save it
+        // Make sure there's no risk of overflow
+        aPolicyDetails.iName.Copy(newName->Left(aPolicyDetails.iName.MaxLength()));
+        }
+    
+    if (newName != NULL) 
+        {
+        CleanupStack::PopAndDestroy(); // newName
+        }
+    
+    LOG(Log::Printf(_L("<- CPolicyStore::DoEnsureUniquePolicyName")));    
+    return nameChanged;
+    }
+
+TBool CPolicyStore::PolicyNameExists(const TDesC& aPolicyName)
+    {
+    LOG_("-> CPolicyStore::PolicyNameExists");
+    TBool policyNameExists = EFalse;
+    
+    // Check the name against the existing names
+    for (TInt i = 0; i < iPolicyListAll->Count(); i++)
+        {
+        // Ignore case in the name comparison
+        if (iPolicyListAll->At(i).iName.CompareF(aPolicyName) == 0)
+            {
+            policyNameExists = ETrue;
+            break;
+            }
+        }
+
+    LOG_("<- CPolicyStore::PolicyNameExists");    
+    return policyNameExists;
+    }
+
+HBufC* CPolicyStore::MakeNewPolicyNameL(const TDes& aOriginalPolicyName, 
+                                     TInt aSequenceNumber)
+    {
+    LOG_("-> CPolicyStore::MakeNewPolicyName");
+
+    const TInt KMaxSequenceNumberStringLength = 32;
+    _LIT(KSequenceNumberFormat, "(%d)");
+    HBufC* sequenceNumberString = HBufC::NewLC(KMaxSequenceNumberStringLength);
+    sequenceNumberString->Des().Format(KSequenceNumberFormat, aSequenceNumber);
+
+    // New name string to be returned
+    HBufC* retBuf(NULL);
+    // Usage of Trim method in PinParser decreases the length by 2 items
+    TInt spaceLeft = aOriginalPolicyName.MaxLength() - 2 - aOriginalPolicyName.Length();
+    TInt sequenceNumberStringLength = sequenceNumberString->Length();
+                                      
+    if (sequenceNumberStringLength <= spaceLeft)
+        {
+        // There's enough free space for the sequence
+        // number, so we can just add append it
+        LOG_1(" Sequence number string: '%S'", &(*sequenceNumberString)); 
+
+        // Determine final string length for dynamic allocation
+        TInt len = aOriginalPolicyName.Length() + sequenceNumberString->Length();
+        retBuf = HBufC::NewLC(len);
+
+        // Construct the final name string
+        TPtr16 ptr = retBuf->Des();
+        ptr.Append(aOriginalPolicyName.Left(aOriginalPolicyName.Length()));
+        ptr.Append(sequenceNumberString->Left(sequenceNumberString->Length()));
+        }
+    else
+        {
+        // There's not enough space for the sequence
+        // number so we override the end of the policy
+        // name with the sequence number
+        TInt lengap = sequenceNumberStringLength - spaceLeft;
+
+        // Determine final string length for dynamic allocation
+        TInt len = aOriginalPolicyName.MaxLength();
+        retBuf = HBufC::NewLC(len);
+
+        // Construct the final name string
+        TPtr16 ptr = retBuf->Des();
+        ptr.Append(aOriginalPolicyName.Left(aOriginalPolicyName.Length() - lengap));
+        ptr.Append(sequenceNumberString->Left(sequenceNumberString->Length()));
+        }
+
+    // Just pop, and delete the non-returned value explicitly
+    CleanupStack::Pop(2); // retBuf, sequenceNumberString
+    delete sequenceNumberString;
+
+    LOG_("<- CPolicyStore::MakeNewPolicyName");
+    return retBuf;
+    }
+
+void CPolicyStore::ReplacePolicyL(const TVpnPolicyId& aPolicyToReplace, const TVpnPolicyId& aReplacingPolicy)
+    {
+    CFileInfoContainer* fileInfo = new (ELeave) CFileInfoContainer();
+    CleanupStack::PushL(fileInfo);
+
+    // Construct PIN and POL file names for
+    // both the old and the new policy
+
+    // Ownership is transferred
+    fileInfo->iPinFileToReplace = iFileUtil.GetPinFileNameL(aPolicyToReplace);
+    fileInfo->iPolFileToReplace = iFileUtil.GetPolFileNameL(aPolicyToReplace);
+
+    fileInfo->iReplacingPinFile = iFileUtil.GetPinFileNameL(aReplacingPolicy);
+    fileInfo->iReplacingPolFile = iFileUtil.GetPolFileNameL(aReplacingPolicy);
+
+
+    // Store the name of the old policy (the original name)
+    TPinParser* pinParser = new (ELeave) TPinParser(iFileUtil);
+    CleanupStack::PushL(pinParser);
+
+    pinParser->ParsePolicyDetailsL(*fileInfo->iPinFileToReplace, fileInfo->iOldPolicyDetails);
+
+    // Delete the old PIN and POL files (note that this
+    // policy is NOT deleted from the policy list)
+    
+    iFileUtil.DeleteFileL(*fileInfo->iPinFileToReplace);
+    iFileUtil.DeleteFileL(*fileInfo->iPolFileToReplace);
+
+    // Rename the new PIN and POL files such
+    // that appear just as updated old files
+    
+    iFileUtil.MoveFileL(*fileInfo->iReplacingPinFile, *fileInfo->iPinFileToReplace);
+    iFileUtil.MoveFileL(*fileInfo->iReplacingPolFile, *fileInfo->iPolFileToReplace);
+
+    // Delete the new policy from the policy list
+    // (it has been imported normally and thus appears in the list)
+    
+    DeletePolicyL(aReplacingPolicy);
+
+    // Because of import, the updated policy has a sequence number in
+    // its name, get rid of this by reverting to the original policy name
+    
+    pinParser->ParsePolicyDetailsL(*fileInfo->iPinFileToReplace, fileInfo->iNewPolicyDetails);
+
+    fileInfo->iNewPolicyDetails.iName.Copy(fileInfo->iOldPolicyDetails.iName);
+
+    HBufC* pinFileContent = pinParser->PolicyDetailsAsTextL(fileInfo->iNewPolicyDetails);
+    CleanupStack::PushL(pinFileContent);
+
+    iFileUtil.SaveFileDataL(*fileInfo->iPinFileToReplace, *pinFileContent);
+
+    CleanupStack::PopAndDestroy(3); // pinFileContent, pinParser, fileInfo
+    }
+
+// New methods to facilitate OMA DM based VPN policy management
+
+void CPolicyStore::AddNewPolicyL(TVpnPolicyDetails& aPolicyDetails, const TDesC8& aPolicyData)
+    {
+    
+    LOG(Log::Printf(_L("-> CPolicyStore::AddNewPolicyL()")));
+    
+    // A non-empty policy name must be given
+    if (aPolicyDetails.iName.Length() == 0)
+        {
+        User::Leave(KErrArgument);
+        }
+
+    // Policy data must be present
+    if (aPolicyData.Length() == 0)
+        {
+        User::Leave(KErrArgument);
+        }
+
+    // If a (globally unique) policy ID
+    // has not been specified, create it
+    if (aPolicyDetails.iId.Length() == 0)
+        {
+        aPolicyDetails.iId.Copy(NewPolicyIdL());
+        }
+                           
+    // If a policy with the same globally unique ID is already
+    // present, then we cannot be adding a new policy
+    if (PolicyIndex(aPolicyDetails.iId) != KUnfoundIndex)
+        {
+        User::Leave(KErrAlreadyExists);
+        }
+
+    DoEnsureUniquePolicyNameL(aPolicyDetails);
+
+    LOG(Log::Printf(_L("Policy name ensured")));                
+                        
+    // Save policy details to the PIN file
+    TPinParser* pinParser = new (ELeave) TPinParser(iFileUtil);
+    CleanupStack::PushL(pinParser);    
+
+    HBufC* pinFileContent = pinParser->PolicyDetailsAsTextL(aPolicyDetails);
+    CleanupStack::PushL(pinFileContent);
+
+    HBufC* pinFile = iFileUtil.GetPinFileNameLC(aPolicyDetails.iId);
+
+    iFileUtil.SaveFileDataL(*pinFile, *pinFileContent);
+
+    CleanupStack::PopAndDestroy(3); // pinFile, pinFileContent, pinParser
+
+    LOG(Log::Printf(_L(" File data saved")));                
+
+    // Save policy data to the POL file    
+
+    HBufC* polFile = iFileUtil.GetPolFileNameLC(aPolicyDetails.iId);
+
+    iFileUtil.SaveFileDataL(*polFile, aPolicyData);
+    CleanupStack::PopAndDestroy(polFile);
+    
+    // Add the policy to the policy list
+    AddPolicyL(aPolicyDetails.iId);
+    LOG(Log::Printf(_L("<- CPolicyStore::AddNewPolicyL()")));
+    }
+
+void CPolicyStore::UpdatePolicyDetailsL(TVpnPolicyDetails& aPolicyDetails)
+    {
+    TVpnPolicyId policyId;
+    policyId.Copy(aPolicyDetails.iId);
+
+    // The caller must specify the ID of the policy to be updated
+    if (policyId.Length() == 0)
+        {
+        User::Leave(KErrArgument);
+        }
+    
+    // A non-empty policy name must be specified, too
+    if (aPolicyDetails.iName.Length() == 0)
+        {
+        User::Leave(KErrArgument);
+        }
+    
+    // Make sure that the specified policy is present
+    TInt policyIndex = PolicyIndex(policyId);
+    if (policyIndex == KUnfoundIndex)
+        {
+        User::Leave(KVpnErrPolicyNotFound);
+        }
+
+    // See if the new name is different from the existing one
+    if (iPolicyListAll->At(policyIndex).iName.CompareF(aPolicyDetails.iName) != 0)
+        {
+        // Make sure that the new name remains to be unique
+        DoEnsureUniquePolicyNameL(aPolicyDetails);
+        }
+    
+    // Save policy details to the PIN file
+    TPinParser* pinParser = new (ELeave) TPinParser(iFileUtil);
+    CleanupStack::PushL(pinParser);
+    
+    HBufC* pinFileContent = pinParser->PolicyDetailsAsTextL(aPolicyDetails);
+    CleanupStack::PushL(pinFileContent);
+
+    HBufC* pinFile = iFileUtil.GetPinFileNameLC(policyId);
+    iFileUtil.SaveFileDataL(*pinFile, *pinFileContent);
+
+    CleanupStack::PopAndDestroy(3); // pinFile, pinFileContent, pinParser
+
+    // Update the policy name in the policy list as the name may have changed
+    iPolicyListAll->At(policyIndex).iName.Copy(aPolicyDetails.iName);
+
+    UpdateVisiblePolicyInfoL(aPolicyDetails);
+    }
+
+void CPolicyStore::UpdateVisiblePolicyInfoL(const TVpnPolicyDetails& aPolicyDetails)
+    {
+    TVpnPolicyId policyId = aPolicyDetails.iId;
+            
+    // Find out whether the policy is hidden or visible
+    TBool isHiddenPolicy = IsHiddenPolicyL(policyId);
+            
+    // See if the policy is in the list of visible ones
+    TInt policyIndexVisible = PolicyIndexVisible(policyId);
+
+    // If the policy is NOT in the visible list
+    if (policyIndexVisible == KUnfoundIndex)
+        {
+        // If the policy is _no_longer_ hidden, add
+        // it to the list of visible policies
+        if (!isHiddenPolicy)
+            {
+            iPolicyListVisible->AppendL(static_cast<TVpnPolicyInfo>(aPolicyDetails));
+            }
+        }
+    else // The policy IS in the visible list
+        {
+        // If the policy is _now_ hidden, remove
+        // it from the list of visible ones
+        if (isHiddenPolicy)
+            {
+            iPolicyListVisible->Delete(policyIndexVisible);
+            iPolicyListVisible->Compress();
+            }
+        else
+            { 
+            // Otherwise update the policy name of the policy in the
+            // list of visible policies as the name may have changed
+            iPolicyListVisible->At(policyIndexVisible).iName.Copy(aPolicyDetails.iName);
+            }
+        }
+    }
+
+void CPolicyStore::UpdatePolicyDataL(
+    const TVpnPolicyId& aPolicyId, const TDesC8& aPolicyData)
+    {
+    // The caller must specify the ID of the policy to be updated
+    if (aPolicyId.Length() == 0)
+        {
+        User::Leave(KErrArgument);
+        }
+
+    // Policy data must be present
+    if (aPolicyData.Length() == 0)
+        {
+        User::Leave(KErrArgument);
+        }
+    
+    // Make sure that the policy is present
+    if (PolicyIndex(aPolicyId) == KUnfoundIndex)
+        {
+        User::Leave(KVpnErrPolicyNotFound);
+        }
+
+    // Save policy data to the POL file
+
+    HBufC* polFile = iFileUtil.GetPolFileNameLC(aPolicyId);
+    iFileUtil.SaveFileDataL(*polFile, aPolicyData);
+    CleanupStack::PopAndDestroy(polFile);
+    }
+
+TBool CPolicyStore::IsHiddenPolicyL(const TVpnPolicyId& aPolicyId)
+    {
+    TVpnPolicyDetails* policyDetails = new (ELeave) TVpnPolicyDetails();
+    CleanupStack::PushL(policyDetails);
+        
+    TPinParser* pinParser = new (ELeave) TPinParser(iFileUtil);
+    CleanupStack::PushL(pinParser);
+
+    HBufC* pinFile = iFileUtil.GetPinFileNameLC(aPolicyId);
+
+    pinParser->ParsePolicyDetailsL(*pinFile, *policyDetails);
+    CleanupStack::PopAndDestroy(2); // pinFile, pinParser
+    
+    // A policy is marked as hidden if it's description 
+    // field contains the "hidden indicator" string
+    if (policyDetails->iDescription.FindF(KHiddenPolicyIndicator) != 
+        KErrNotFound)
+        {
+        CleanupStack::PopAndDestroy(); // policyDetails
+        return ETrue;
+        }
+    else
+        {
+        CleanupStack::PopAndDestroy(); // policyDetails
+        return EFalse;
+        }
+    }