vpnengine/vpnmanager/src/policypatcher.cpp
changeset 0 33413c0669b9
child 2 ef893827b4d1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/vpnmanager/src/policypatcher.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,484 @@
+/*
+* Copyright (c) 2003-2008 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 importer
+*
+*/
+
+
+
+#include "policypatcher.h"
+#include "vpnapidefs.h"
+
+
+TAny* TPatchKeyArrayPtr::At(TInt aIndex) const
+    {
+    if (aIndex==KIndexPtr)
+        {
+        TAny* base = *(TUint8**)iPtr;
+        CPolicyPatchInfo* info = (CPolicyPatchInfo*)base;
+        return (TAny*)&(info->iPatchOffset);
+        }
+    else
+        {
+        TAny* base = *(TUint8**)iBase->Ptr(aIndex*sizeof(TUint8**)).Ptr();
+        CPolicyPatchInfo* info = (CPolicyPatchInfo*)base;
+        return (TAny*)&(info->iPatchOffset);
+        }
+    }
+
+
+CPolicyPatcher* CPolicyPatcher::NewL()
+    {
+    CPolicyPatcher* self = new (ELeave) CPolicyPatcher();
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+CPolicyPatcher::CPolicyPatcher()
+    {
+    }
+
+CPolicyPatcher::~CPolicyPatcher()
+    {
+    }
+
+void CPolicyPatcher::ConstructL()
+    {
+    }
+
+/*
+ * The policy file is patched as follows:
+ * - CA certificate references are changed from filenames
+ *   into CA subject names (correspondingly, the reference
+ *   type is changed from BIN to NAME)
+ * - User private key and certificate references are not
+ *   removed although they are no longer in use
+ */
+HBufC8* CPolicyPatcher::PatchPolicyL(const TDesC8& aPolicyData,
+                                     CPolicyPatchInfoList* aPatchInfoList)
+    {
+    iInput.Set(aPolicyData);
+    iPatchInfoList = aPatchInfoList;
+
+    FindOffsetsL();
+
+    // Sort the resulting array to ascending order, using key
+    // patchInfo->iPatchOffset
+    TPatchKeyArrayPtr sortedCerts(_FOFF(CPatchData, iPatchOffset), ECmpTInt32);
+    iPatchInfoList->Sort(sortedCerts);
+
+    return CreateOutputL();
+    }
+
+void CPolicyPatcher::FindOffsetsL()
+    {
+    TInt formatValueOffset = KErrGeneral;
+
+    for (TInt i = 0; i < iPatchInfoList->Count(); i++)
+        {
+        CPolicyPatchInfo* patchInfo = iPatchInfoList->At(i);
+
+        TInt fileNameOffset = iInput.FindF(patchInfo->iCertFileName);
+
+        if (fileNameOffset != KErrNotFound)
+            {
+            TPtrC8 precedingInput = iInput.Left(fileNameOffset);
+
+            if (0 == patchInfo->UserCertKeyLen())
+                {
+                // CA cert
+                formatValueOffset = precedingInput.LocateReverseF(KBinChar);
+                }
+            else
+                {
+                // User cert
+                formatValueOffset = precedingInput.LocateReverseF(KFormatChar);
+                }
+
+            if (formatValueOffset != KErrNone)
+                {
+                patchInfo->iPatchOffset = formatValueOffset;
+                }
+            else
+                {
+                User::Leave(KVpnErrInvalidPolicyFile);
+                }
+
+            patchInfo->iReminderOffset = fileNameOffset + patchInfo->iCertFileName.Length();
+            }
+        }
+    }
+
+HBufC8* CPolicyPatcher::CreateOutputL()
+    {
+    TInt patchInfoCount = iPatchInfoList->Count();
+
+    CPatchDataList* patchDataList = new (ELeave) CPatchDataList(2);
+    CleanupStack::PushL(patchDataList);
+
+    for (TInt i = 0; i < patchInfoCount; i++)
+        {
+        CPolicyPatchInfo* patchInfo = iPatchInfoList->At(i);
+
+        if (patchInfo->iPatchOffset != KUndefinedOffset)
+            {
+            CPatchData* patchData = new (ELeave) CPatchData;
+            CleanupStack::PushL(patchData);
+
+            patchData->iPatchOffset = patchInfo->iPatchOffset;
+            patchData->iReminderOffset = patchInfo->iReminderOffset;
+            patchData->iData = CreatePatchDataL(patchInfo);
+
+            patchDataList->AppendL(patchData);
+
+            CleanupStack::Pop(); // patchData (now owned by the list)
+            }
+        }
+
+    TInt outputLength = iInput.Length();
+    TInt patchDataCount = patchDataList->Count();
+
+    for (TInt j = 0; j < patchDataCount; j++)
+        {
+        outputLength += patchDataList->At(j)->iData->Length();
+        }
+
+    HBufC8* output = HBufC8::NewL(outputLength);
+    TPtr8 ptrOutput = output->Des();
+
+    if (patchDataCount == 0)
+        {
+        ptrOutput.Append(iInput);
+        }
+    else
+        {
+        // Append all patches and the input data before,
+        // between and after them to the outout
+        for (TInt k = 0; k < patchDataCount; k++)
+            {
+            TInt startOffset;
+
+            // If this is the first patch...
+            if (k == 0)
+                {
+                // ...there is no previous patch whose
+                // reminder offset we could use
+                startOffset = 0;
+                }
+            else
+                {
+                // There is a previous patch whose reminder offset we can use
+                startOffset = patchDataList->At(k - 1)->iReminderOffset;
+                }
+
+            CPatchData* currPatchData = patchDataList->At(k);
+
+            TInt endOffset = currPatchData->iPatchOffset;
+
+            // Append to the output the input data between the previous
+            // patch (or the beginning of input if this is the first patch)
+            // and the current patch
+            ptrOutput.Append(iInput.Mid(startOffset, endOffset - startOffset));
+
+            // Append the current patch data to the output
+            ptrOutput.Append(*(currPatchData->iData));
+
+            // If this is the last patch...
+            if (k == (patchDataCount -1))
+                {
+                if(EFalse != iUserCertPatched)
+                    {
+                    // The data after user cert patch is not needed.
+                    // Append new line instead.
+                    // In practise this removes the PRIVATE_KEY_FORMAT
+                    // and PRIVATE_KEY_DATA lines.
+                    ptrOutput.Append(KNewLine);
+                    }
+                else
+                    {
+                    // ...append to the output the input data between the
+                    // last patch and the end of the input
+                    ptrOutput.Append(iInput.Mid(currPatchData->iReminderOffset));
+                    }
+                }
+            }
+        }
+
+    CleanupStack::PopAndDestroy(); // patchDataList
+
+    return output;
+    }
+
+HBufC8* CPolicyPatcher::CreatePatchDataL(const CPolicyPatchInfo* aPatchInfo)
+    {
+    TInt patchDataLength = 0;
+
+    TBuf8<20> keyBuf;
+
+    const TDesC8& certSubjectName = aPatchInfo->CertSubjectName();
+
+    if (0 == aPatchInfo->UserCertKeyLen())
+        {
+        // CA cert patch
+        patchDataLength = KName().Length() + KNewLine().Length() +
+                          KDataField().Length() + KSpace().Length() +
+                          certSubjectName.Length();
+        }
+    else
+        {
+        // user cert patch
+        keyBuf.Num(aPatchInfo->UserCertKeyLen());
+        patchDataLength = KDNField().Length() + certSubjectName.Length() +
+                          KNewLine().Length() + KKeyLenField().Length() +
+                          keyBuf.Length();
+        }
+
+    HBufC8* patchData = HBufC8::NewL(patchDataLength);
+    CleanupStack::PushL(patchData);
+
+    TPtr8 ptrPatchData(patchData->Des());
+
+    if (0 == aPatchInfo->UserCertKeyLen())
+        {
+        // CA cert patch
+        ptrPatchData.Append(KName);
+        ptrPatchData.Append(KNewLine);
+        ptrPatchData.Append(KDataField);
+        ptrPatchData.Append(KSpace);
+        ptrPatchData.Append(certSubjectName);
+        }
+    else
+        {
+        // User cert patch
+        ptrPatchData.Append(KKeyLenField);
+        ptrPatchData.Append(keyBuf);
+        ptrPatchData.Append(KNewLine);
+        ptrPatchData.Append(KDNField);
+        ptrPatchData.Append(certSubjectName);
+        iUserCertPatched = ETrue;
+        }
+
+    CleanupStack::Pop(); // patchData
+
+    return patchData;
+    }
+
+
+// CPolicyPatchInfo
+
+CPolicyPatchInfo::CPolicyPatchInfo()
+    {
+    iCertFileName.SetLength(0);
+    iPatchOffset = KUndefinedOffset;
+    iReminderOffset = KUndefinedOffset;
+    iUserCertKeyLen = 0;
+    }
+
+CPolicyPatchInfo::~CPolicyPatchInfo()
+    {
+    delete iCertSubjectName;
+    }
+
+const TDesC8& CPolicyPatchInfo::CertSubjectName() const
+    {
+    return *iCertSubjectName;
+    }
+
+void CPolicyPatchInfo::SetCertSubjectNameL(const TDesC8& aCertSubjectName)
+    {
+    delete iCertSubjectName;
+    iCertSubjectName = NULL;
+    HBufC8* certSubjectBuf = CheckSubjectNameSyntaxL(aCertSubjectName);  
+    iCertSubjectName = certSubjectBuf;
+    }
+
+void CPolicyPatchInfo::SetUserCertKeyLen(TInt aKeyLen)
+    {
+    iUserCertKeyLen = aKeyLen;
+    }
+
+TInt CPolicyPatchInfo::UserCertKeyLen() const
+    {
+    return iUserCertKeyLen;
+    }
+    
+HBufC8* CPolicyPatchInfo::CheckSubjectNameSyntaxL(const TDesC8& aSubj)
+    {
+    const TInt KMaxSubjectItems = 20;
+    
+    _LIT8(KEqualSign, "=");
+    _LIT8(KCommaSign, ",");
+    _LIT8(KReplacementChar, "\"");
+    
+    //counts positions for equal sign characters
+    CArrayFixFlat<TInt>* equalSignArr=new (ELeave) CArrayFixFlat<TInt> (KMaxSubjectItems); 
+    
+    //counts positions for comma characters
+    CArrayFixFlat<TInt>* commaSignArr=new (ELeave) CArrayFixFlat<TInt> (KMaxSubjectItems); 
+    
+    //counts positions for double quatiation characters
+    CArrayFixFlat<TInt>* updateArr=new (ELeave) CArrayFixFlat<TInt> (KMaxSubjectItems);
+    
+    TInt subjLth=aSubj.Length();
+    TInt equalArrItemCount=0;
+    TInt commaArrItemCount=0;
+    TInt updateArrCount=0;
+    
+    CleanupStack::PushL(equalSignArr);
+    CleanupStack::PushL(commaSignArr);
+    
+    //register '=' and ',' character positions 
+    for (TInt i=0; i<subjLth; i++)
+        {
+        if ( aSubj.Mid(i, 1)== KEqualSign )
+            {
+            equalSignArr->AppendL(i);
+            equalArrItemCount++;
+            }
+        
+        if ( aSubj.Mid(i, 1)== KCommaSign )
+            {
+            commaSignArr->AppendL(i);
+            commaArrItemCount++;
+            }
+        }
+    
+    CleanupStack::PushL(updateArr);
+    
+    TInt i=0;
+    TInt j=0;
+    
+    // At least one comma required. Otherwise there is no chance for extra commas
+    if ( commaArrItemCount )
+        {
+        while ( i< equalArrItemCount )
+            {
+            
+            //advance starting position for every iteration
+            TInt eqSignStartIndex=i;
+            
+            TInt cmCount=0;
+        
+            //check wether there is more than one comma between two adjacent fields.
+            while ( commaSignArr->At(j)< equalSignArr->At(eqSignStartIndex) )
+                {
+                cmCount++;
+                
+                j++;
+                
+                if ( j==commaArrItemCount )
+                    break;
+                }
+            
+            //at least one extra comma character found. Mark positions for mofifications.
+            if (cmCount>1)
+                {
+                TInt equalPos=equalSignArr->At(eqSignStartIndex-1) + 1;
+                updateArr->AppendL(equalPos);
+                
+                TInt commaPos=commaSignArr->At(j-1);
+                updateArr->AppendL(commaPos);
+                
+                updateArrCount++;
+                updateArrCount++;
+                }
+            i++;    
+            }
+        }
+        
+        //Checking also last attribute of Subject Name string
+        if ( j<commaArrItemCount )
+            {
+            updateArr->AppendL(equalSignArr->At(equalArrItemCount-1));
+            updateArr->AppendL(subjLth-1);
+            }
+       
+       TBuf8<256> resultBuf;
+       resultBuf.Copy(aSubj);
+       
+       i=0;       
+       
+       //update subjectname acoording to updateArr array.
+       if ( updateArr->Count()>0 )
+           {
+           while (i<updateArrCount)
+               {
+               TBuf8<3> updateStr(KReplacementChar);
+               
+               updateStr.Append(aSubj.Mid(updateArr->At(i),1));
+               
+               if ( resultBuf.Length()<256 )
+                   resultBuf.Insert(updateArr->At(i) + i, KReplacementChar);
+               else
+                   User::Leave(KErrNotSupported);
+               i++;
+               }
+           }
+       
+       CleanupStack::Pop(updateArr);
+       CleanupStack::Pop(commaSignArr);
+       CleanupStack::Pop(equalSignArr);
+       
+       delete equalSignArr;
+       equalSignArr=NULL;
+       
+       delete commaSignArr;
+       commaSignArr=NULL;
+       
+       delete updateArr;
+       updateArr=NULL;
+       
+       HBufC8* resultHeap = resultBuf.AllocL();
+       
+       return resultHeap;
+    }
+
+
+// CPolicyPatchInfoList
+
+CPolicyPatchInfoList::CPolicyPatchInfoList(TInt aGranularity)
+    : CArrayPtrFlat<CPolicyPatchInfo>(aGranularity)
+    {
+    }
+
+CPolicyPatchInfoList::~CPolicyPatchInfoList()
+    {
+    ResetAndDestroy();
+    }
+
+
+// CPatchData
+
+CPatchData::~CPatchData()
+    {
+    delete iData;
+    }
+
+
+// CPatchDataList
+
+CPatchDataList::CPatchDataList(TInt aGranularity)
+    : CArrayPtrFlat<CPatchData>(aGranularity)
+    {
+    }
+
+CPatchDataList::~CPatchDataList()
+    {
+    ResetAndDestroy();
+    }
+
+
+/***/