vpnengine/vpnipsecpolparser/src/ipsecpolparser.cpp
changeset 0 33413c0669b9
child 23 473321461bba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/vpnipsecpolparser/src/ipsecpolparser.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,2068 @@
+/*
+* Copyright (c) 2002-2005 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: IPSec policy parser main module.
+* A parser for IPsec policies. Converts textual IPsec policies into 
+* in-memory data structures and vice versa. 
+*
+*/
+
+
+
+#include <e32std.h>
+#include <coeutils.h>
+
+#include "ipsecpolparser.h"
+#include "logvpncommon.h"
+
+// Policies Parsing
+
+// Symbian change - start
+#ifdef __VC32__
+#pragma warning(disable : 4097) // typedef-name used as synonym for class-name
+#endif
+// Symbian change - end
+
+EXPORT_C
+TPolicyParser::TPolicyParser(const TDesC &aPolicy) : TLex(aPolicy)
+    {}
+
+EXPORT_C TInt
+TPolicyParser::ParseL(CIpSecurityPiece* aPieceData)
+    {
+    LOG_("TPolicyParser::ParseL()\n");
+    TInt err(KErrNone);
+    iLine = 1;
+
+    CSecurityPolicy* sp = aPieceData->Policies();
+    while (!err && NextToken() == token_string)
+        {
+        if (iToken.Compare(_L("sa")) == 0)
+            {
+            err = parse_sa_specL(sp);
+            }
+        else if (iToken.Compare(_L("ep")) == 0)
+            {
+            err = parse_ep_specL(sp);
+            }
+        else
+            {
+            err = parse_conn2saL(sp);
+            }
+        }
+
+    if (!err && !Eos())
+        {
+        // Parsing didn't detect error, but not all parsed!
+        err = KErrGeneral;
+        }
+
+    if (err)
+        {
+        if (iMsg.Length() > 0 && iMsg.Length() < 200)
+            {
+            aPieceData->iErrorInfo.Copy(iMsg);
+            }
+        }
+
+    return (err);
+    }
+
+EXPORT_C TInt
+TPolicyParser::BufferAppend(HBufC8*& aPolBfr, const TDesC8& aText)
+    {
+    LOG_("TPolicyParser::BufferAppend()\n");
+    TInt err(KErrNone);
+
+    // Make sure that we have enough space for the new text
+    TInt spaceLeft = aPolBfr->Des().MaxLength() - aPolBfr->Des().Length();
+    if (aText.Length() > spaceLeft)
+        {
+        // Allocate enough space for the new text + some additional
+        // free space so that allocations are not too frequent
+        TInt newMaxLength = aPolBfr->Des().MaxLength()
+                            + aText.Length()
+                            + KPolicyBufferSizeIncrement;
+        HBufC8* tempBfr = aPolBfr->ReAlloc(newMaxLength);
+        if (tempBfr != NULL)
+            {
+            aPolBfr = tempBfr;
+            }
+        else
+            {
+            return KErrNoMemory;
+            }
+        }
+
+    aPolBfr->Des().Append(aText);
+    return err;
+    }
+
+EXPORT_C TInt
+TPolicyParser::Write(CSecurityPolicy *aSp,
+                     HBufC8*& aPolBfr,
+                     TBool aSortingOrder)
+    {
+    LOG_("TPolicyParser::Write()\n");
+    TInt err = WriteSAs(aSp->SAList(), aPolBfr);
+    if (err)
+        {
+        return err;
+        }
+    
+    if (aSortingOrder)
+        {
+        err = WriteSelectorsInSortingOrder(aSp->SelectorList(),
+                                           aPolBfr,
+                                           aSortingOrder);
+        }
+    else
+        {
+        err = WriteSelectors(aSp->SelectorList(), aPolBfr, aSortingOrder);
+        }
+        
+    return err;
+    }
+
+TInt
+TPolicyParser::WriteSAs(CSAList* aSAList, HBufC8*& aPolBfr)
+    {
+    LOG_("TPolicyParser::WriteSAs()\n");
+    TBuf8<1024> aux;
+    TInt err(KErrNone);
+    TInt count = aSAList->Count();
+    for (TInt i = 0; i < count ; i++)
+        {
+        TextSA(aSAList->At(i), aux);
+        err = BufferAppend(aPolBfr, aux);
+        if (err != KErrNone)
+            {
+            return err;
+            }
+        }
+    return KErrNone;
+    }
+
+void
+TPolicyParser::TextSA(CPolicySpec* aSA, TDes8& aBuf)
+    {
+    LOG_("TPolicyParser::TextSA()\n");
+    if (aSA->iSpectype == EPolSpecSA)
+        {
+        aBuf.Format(_L8("sa "));
+        // SA name
+        aBuf.Append(aSA->iName->Des());
+        aBuf.Append(_L8(" = {\n"));
+        switch (aSA->iSpec.iType)
+            {
+            case SADB_SATYPE_AH:
+                aBuf.Append(_L8(" ah\n"));
+                break;
+            case SADB_SATYPE_ESP:
+                aBuf.Append(_L8(" esp\n"));
+                break;
+            default:        //SADB_SATYPE_UNSPEC
+                aBuf.Append(_L8(" ???")); //Shouldn't happen
+            }
+
+        // Encryption Algorithm
+
+
+
+        if (aSA->iSpec.iEalg != 0)
+            {
+            // Encryption Alg
+            aBuf.AppendFormat(_L8(" encrypt_alg %d\n"), aSA->iSpec.iEalg);
+            }
+
+        if (aSA->iSpec.iEalgLen != 0)
+            {
+            aBuf.AppendFormat(_L8(" max_encrypt_bits %d\n"), aSA->iSpec.iEalgLen);
+            }
+
+        // Authentication Algorithm
+        if (aSA->iSpec.iAalg != 0)
+            {
+            aBuf.AppendFormat(_L8(" auth_alg %d\n"), aSA->iSpec.iAalg);
+            }
+
+        if (aSA->iSpec.iAalgLen != 0)
+            {
+            aBuf.AppendFormat(_L8(" max_auth_bits %d\n"), aSA->iSpec.iAalgLen);
+            }
+
+        if (aSA->iSpec.iPfs != 0)
+            {
+            aBuf.Append(_L8(" pfs\n"));
+            }
+
+        if (aSA->iRemoteIdentity != NULL)
+            {
+            aBuf.Append(_L8(" identity_remote "));
+            aBuf.Append(aSA->iRemoteIdentity->Des());
+            aBuf.Append('\n');
+            }
+
+        if (aSA->iLocalIdentity != NULL)
+            {
+            aBuf.Append(_L8(" identity_local "));
+            aBuf.Append(aSA->iLocalIdentity->Des());
+            aBuf.Append('\n');
+            }
+
+        if (aSA->iSpec.iReplayWindowLength != 0)
+            {
+            aBuf.AppendFormat(_L8(" replay_win_len %d\n"),
+                              aSA->iSpec.iReplayWindowLength);
+            }
+
+        if (aSA->iSpec.iMatchProtocol != 0)
+            {
+            aBuf.Append(_L8(" protocol_specific\n"));
+            }
+
+        if (aSA->iSpec.iMatchLocalPort != 0)
+            {
+            aBuf.Append(_L8(" local_port_specific\n"));
+            }
+
+        if (aSA->iSpec.iMatchRemotePort != 0)
+            {
+            aBuf.Append(_L8(" remote_port_specific\n"));
+            }
+
+        if (aSA->iSpec.iMatchProxy != 0)
+            {
+            aBuf.Append(_L8(" proxy_specific\n"));
+            }
+
+        if (aSA->iSpec.iMatchSrc != 0)
+            {
+            aBuf.Append(_L8(" src_specific\n"));
+            }
+
+        if (aSA->iSpec.iMatchLocal != 0)
+            {
+            aBuf.Append(_L8(" local_specific\n"));
+            }
+
+        if (aSA->iSpec.iMatchRemote != 0)
+            {
+            aBuf.Append(_L8(" remote_specific\n"));
+            }
+
+        if (aSA->iSpec.iHard.sadb_lifetime_allocations != 0)
+            {
+            aBuf.AppendFormat(_L8(" hard_lifetime_allocations %d\n"),
+                              aSA->iSpec.iHard.sadb_lifetime_allocations);
+            }
+
+        if (aSA->iSpec.iHard.sadb_lifetime_bytes != 0)
+            {
+            aBuf.AppendFormat(_L8(" hard_lifetime_bytes %d\n"),
+                              aSA->iSpec.iHard.sadb_lifetime_bytes);
+            }
+
+        if (aSA->iSpec.iHard.sadb_lifetime_addtime != 0)
+            {
+            aBuf.AppendFormat(_L8(" hard_lifetime_addtime %d\n"),
+                              aSA->iSpec.iHard.sadb_lifetime_addtime);
+            }
+
+        if (aSA->iSpec.iHard.sadb_lifetime_usetime != 0)
+            {
+            aBuf.AppendFormat(_L8(" hard_lifetime_usetime %d\n"),
+                              aSA->iSpec.iHard.sadb_lifetime_usetime);
+            }
+
+        if (aSA->iSpec.iSoft.sadb_lifetime_allocations != 0)
+            {
+            aBuf.AppendFormat(_L8(" soft_lifetime_allocations %d\n"),
+                              aSA->iSpec.iSoft.sadb_lifetime_allocations);
+            }
+
+        if (aSA->iSpec.iSoft.sadb_lifetime_bytes != 0)
+            {
+            aBuf.AppendFormat(_L8(" soft_lifetime_bytes %d\n"),
+                              aSA->iSpec.iSoft.sadb_lifetime_bytes);
+            }
+
+        if (aSA->iSpec.iSoft.sadb_lifetime_addtime != 0)
+            {
+            aBuf.AppendFormat(_L8(" soft_lifetime_addtime %d\n"),
+                              aSA->iSpec.iSoft.sadb_lifetime_addtime);
+            }
+
+        if (aSA->iSpec.iSoft.sadb_lifetime_usetime != 0)
+            {
+            aBuf.AppendFormat(_L8(" soft_lifetime_usetime %d\n"),
+                              aSA->iSpec.iSoft.sadb_lifetime_usetime);
+            }
+        aBuf.AppendFormat(_L8(" }\n\n"));
+        }
+    else
+        {
+        TBuf<39> addr;
+        aBuf.Format(_L8("ep "));
+
+        // EndPoint name
+        aBuf.Append(aSA->iName->Des());
+        aBuf.Append(_L8(" = {"));
+
+        if (aSA->iEpSpec.iIsOptional)
+            {
+            aBuf.Append(_L8(" ? "));
+            }
+        aSA->iEpSpec.iEpAddr.OutputWithScope(addr);
+        aBuf.Append(addr);
+        aBuf.Append(_L8(" }\n\n"));
+        }
+    }
+
+TInt
+TPolicyParser::WriteSelectors(CSelectorList* aSelList,
+                              HBufC8*& aPolBfr,
+                              TBool /* aSortingOrder */)
+    {
+    LOG_("TPolicyParser::WriteSelectors()\n");
+    TBuf8<1024> aux;
+    TInt err(KErrNone);
+    TInt count(aSelList->Count());
+    for (TInt i = 0; i < count; i++)
+        {
+        aux.Zero();
+        CPolicySelector* ps = aSelList->At(i);
+
+        // Bypass the selector, if sequence number is 0xFFFFFFFF.
+        // This sequence number indicates that the selector
+        // is of type 'bypass/drop_everything_else'
+        if (ps->iSequenceNumber == 0xFFFFFFFF)
+            {
+            continue;
+            }
+            
+        // Convert selector to text format and print it into buffer 
+        TextSel(ps, aux, EFalse);
+        err = BufferAppend(aPolBfr, aux);
+        if (err != KErrNone)
+            {
+            return err;
+            }
+        }
+
+    // All selectors have been written
+    err = BufferAppend(aPolBfr, (_L8("\n")));
+    return (err);
+    }
+
+///////////////////////////////////////////////////////////////////
+//  This function writes the selectors to a file according
+//  to the sequence numbers available in the CPolicySelector.
+///////////////////////////////////////////////////////////////////
+//
+TInt
+TPolicyParser::WriteSelectorsInSortingOrder(
+    CSelectorList* aSelList,
+    HBufC8*& aPolBfr,
+    TBool /* aSortingOrder */)
+    {
+    LOG_("TPolicyParser::WriteSelectorsInSortingOrder()\n");
+    TInt err(KErrNone);
+    TInt count(aSelList->Count());
+    TInt currentSequenceNumber(1);
+
+    // Loop here until all selectors have been written
+    TBool found = ETrue;
+    while (found)
+        {
+        found = EFalse;
+
+        // Loop through the selector list and search the
+        // the selector corresponding to the current sequence number
+        for (TInt i = 0; i < count; i++)
+            {
+            TBuf8<1024> aux;
+            aux.Zero();
+            CPolicySelector* ps = aSelList->At(i);
+            
+            if (ps->iSequenceNumber == currentSequenceNumber)
+                {
+                // Build a selector output string
+                TextSel(ps, aux, ETrue);
+
+                // Write a string to the file
+                err = BufferAppend(aPolBfr, aux);
+                if (err != KErrNone)
+                    {
+                    return err;
+                    }
+                // Prepare for the next selector
+                currentSequenceNumber++;
+                found = ETrue;
+                break;
+                }
+            }
+        }
+
+    // All selectors have been written
+    err = BufferAppend(aPolBfr, (_L8("\n")));
+    return (err);
+    }
+
+///////////////////////////////////////////////////////////////////
+// Prints the supplied selector into a given buffer in text format
+///////////////////////////////////////////////////////////////////
+//
+void
+TPolicyParser::TextSel(CPolicySelector* aSel,
+                       TDes8& aBuf,
+                       TBool aOrdered)
+    {
+    LOG_("TPolicyParser::TextSel()\n");
+    aBuf.Format(_L8(" "));
+
+    if (aSel->iIsFinal)
+        {
+        aBuf.Append(_L8(" final "));
+        }
+
+    if (aSel->iIsMerge)
+        {
+        aBuf.Append(_L8(" merge "));
+        }
+
+    // NOTE:
+    //  This is a kludge to save the global selector definition
+    //  when policy is loaded/parsed and then finally cached into 
+    //  a list in text format. When combined policy is build 
+    //  before sending it to IPSEC6.PRT component, the selector
+    //  list is ordered so this definition is then not included
+    //  in the policy text that is sent into the protocol component
+    if (aSel->iGlobalSelector && !aOrdered)
+        {
+        aBuf.Append(_L8(" scope:global "));
+        }
+
+    switch (aSel->iDirection)
+        {
+        default:
+            break;
+
+        case KPolicySelector_SYMMETRIC:
+            break;
+
+        case KPolicySelector_INBOUND:
+            aBuf.Append(_L8(" inbound "));
+            break;
+
+        case KPolicySelector_OUTBOUND:
+            aBuf.Append(_L8(" outbound "));
+            break;
+
+        case KPolicySelector_INTERFACE:
+            TBuf8<20> name;
+            name.Copy(aSel->iInterface);
+            aBuf.Append(_L8(" if "));
+            aBuf.Append(name);
+            aBuf.Append(_L8(" "));
+            break;
+        }
+
+    // Check if remote address exists and no interface name defined
+    if (aSel->iDirection != KPolicySelector_INTERFACE 
+        && aSel->iRemote.Family() != KAFUnspec)
+        {
+        TBuf<39> addr;
+        TBuf<39> mask;
+
+        aSel->iRemote.OutputWithScope(addr);
+        aSel->iRemoteMask.OutputWithScope(mask);
+        
+        // Add remote address/mask with scope into the buffer        
+        aBuf.Append(_L8(" remote "));
+        aBuf.Append(addr);
+        aBuf.Append(_L8(" "));
+        aBuf.Append(mask);
+        }
+    else 
+        {
+        if (aSel->iRemSelEpName != NULL)
+            {
+            // Remote Endpoint name exists so add it into the buffer
+            aBuf.Append(_L8(" remote "));
+            aBuf.Append(aSel->iRemSelEpName->Des());
+            }
+        if (aSel->iRemMaskEpName != NULL)
+            {
+            aBuf.Append(_L8(" "));
+            aBuf.Append(aSel->iRemMaskEpName->Des());
+            }
+        }
+
+    // Check if local address exists and no interface name defined
+    if (aSel->iDirection != KPolicySelector_INTERFACE 
+        && aSel->iLocal.Family() != KAFUnspec)
+        {
+        TBuf<39> addr;
+        TBuf<39> mask;
+        
+        aSel->iLocal.OutputWithScope(addr);
+        aSel->iLocalMask.OutputWithScope(mask);
+
+        // Add local address/mask with scope into the buffer        
+        aBuf.Append(_L8(" local "));
+        aBuf.Append(addr);
+        aBuf.Append(_L8(" "));
+        aBuf.Append(mask);
+        }
+    else 
+        {
+        if (aSel->iLocSelEpName != NULL)
+            {
+            // Local Endpoint name exists so add it into the buffer
+            aBuf.Append(_L8(" local "));
+            aBuf.Append(aSel->iLocSelEpName->Des());
+            }
+        if (aSel->iLocMaskEpName != NULL)
+            {
+            aBuf.Append(_L8(" "));
+            aBuf.Append(aSel->iLocMaskEpName->Des());
+            }
+        }
+
+    if (aSel->iProtocol != 0)
+        {
+        aBuf.AppendFormat(_L8(" protocol %d "), aSel->iProtocol);
+        }
+
+    if (aSel->iLocal.Port() != 0)
+        {
+        aBuf.AppendFormat(_L8(" local_port %d "), aSel->iLocal.Port());
+        }
+
+    if (aSel->iRemote.Port() != 0)
+        {
+        aBuf.AppendFormat(_L8(" remote_port %d "), aSel->iRemote.Port());
+        }
+
+    if (aSel->iIcmpType != -1)
+        {
+        aBuf.AppendFormat(_L8(" icmp_type %d "), aSel->iIcmpType);
+        }
+
+    if (aSel->iType != -1)
+        {
+        aBuf.AppendFormat(_L8(" type %d "), aSel->iType);
+        }
+
+    if (aSel->iIcmpCode != -1)
+        {
+        aBuf.AppendFormat(_L8(" icmp_code %d "), aSel->iIcmpCode);
+        }
+
+    if (aSel->iDropAction)
+        {
+        aBuf.Append(_L8(" = drop\n "));
+        return ;
+        }
+
+    aBuf.Append(_L8(" = { "));
+
+    TSecpolBundleIter iterl(aSel->iBundle);
+    CSecpolBundleItem* iteml(NULL);
+    while ((iteml = iterl++) != NULL)
+        {
+        if (iteml->iSpec != NULL)
+            aBuf.Append(*iteml->iSpec->iName);
+        else
+            aBuf.Append(_L8(" tunnel"));
+
+        aBuf.Append(_L8("("));
+
+        if (!iteml->iTunnel.IsUnspecified())
+            {
+            TBuf<39> addr;
+            iteml->iTunnel.OutputWithScope(addr);
+            aBuf.Append(addr);
+            }
+        else if (iteml->iTunnelEpName != NULL)
+            {
+            aBuf.Append(iteml->iTunnelEpName->Des());
+            }
+        aBuf.Append(_L8(") "));
+        }
+
+    aBuf.Append(_L8(" }\n"));
+    }
+
+void
+TPolicyParser::Error(TRefByValue<const TDesC> aFmt, ...)
+    {
+    VA_LIST list;
+    VA_START(list, aFmt);
+    iMsg.FormatList(aFmt, list);
+    iMsg += (_L(" at line "));
+    iMsg.AppendNum(iLine);
+    };
+
+//
+// Skip white space and mark, including comments!
+//
+void
+TPolicyParser::SkipSpaceAndMark()
+    {
+    TChar ch;
+    TInt comment = 0;
+
+    while (!Eos())
+        {
+        ch = Get();
+        if (ch == '\n')
+            {
+            iLine++;
+            comment = 0;
+            }
+        else if (comment || ch == '#')
+            comment = 1;
+        else if (!ch.IsSpace())
+            {
+            UnGet();
+            break;
+            }
+        }
+    Mark();
+    }
+
+//
+//
+token_type TPolicyParser::NextToken()
+    {
+    TChar ch;
+    token_type val;
+
+    SkipSpaceAndMark();
+    if (Eos())
+        {
+        val = token_eof;
+        }
+    else
+        {
+        ch = Get();
+        if (ch == '{')
+            val = token_brace_left;
+        else if (ch == '}')
+            val = token_brace_right;
+        else if (ch == '(')
+            val = token_par_left;
+        else if (ch == ')')
+            val = token_par_right;
+        else if (ch == '=')
+            val = token_equal;
+        else if (ch == ',')
+            val = token_comma;
+        else
+            {
+            val = token_string;
+            while (!Eos())
+                {
+                ch = Peek();
+                if (ch == '{' || ch == '}' ||
+                    ch == '(' || ch == ')' ||
+                    ch == '=' || ch == '#' || ch.IsSpace())
+                    break;
+                Inc();
+                }
+            }
+        }
+    iToken.Set(MarkedToken());
+    SkipSpaceAndMark();
+    return (val);
+    }
+
+TInt
+TPolicyParser::parse_sa_spec_paramsL(CPolicySpec& aSpec)
+    {
+    LOG_("TPolicyParser::parse_sa_spec_paramsL()\n");
+    TInt sa_type_defined(0);
+    TInt err(KErrNone);
+    token_type val;
+
+    while ((val = NextToken()) == token_string)
+        {
+        if (iToken.Compare(_L("ah")) == 0)
+            {
+            sa_type_defined++;
+            aSpec.iSpec.iType = SADB_SATYPE_AH;
+            }
+        else if (iToken.Compare(_L("esp")) == 0)
+            {
+            sa_type_defined++;
+            aSpec.iSpec.iType = SADB_SATYPE_ESP;
+            }
+        else if (iToken.Compare(_L("encrypt_alg")) == 0)
+            {
+            err = Val(aSpec.iSpec.iEalg, EDecimal);
+            if ((err != KErrNone) || (aSpec.iSpec.iEalg > MAX_EALG_VALUE))
+                {
+                Error(_L("invalid encrypt alg %d"), (TUint)aSpec.iSpec.iEalg);
+                return (KErrGeneral);
+                }
+            }
+        else if (iToken.Compare(_L("max_encrypt_bits")) == 0)
+            {
+            err = Val(aSpec.iSpec.iEalgLen, EDecimal);
+            if (err != KErrNone)
+                {
+                Error(_L("invalid encrypt alg key length %d"),
+                      aSpec.iSpec.iEalgLen);
+                return (KErrGeneral);
+                }
+            }
+        else if (iToken.Compare(_L("auth_alg")) == 0)
+            {
+            err = Val(aSpec.iSpec.iAalg, EDecimal);
+            if (err != KErrNone)
+                {
+                Error(_L("invalid auth alg %d"), aSpec.iSpec.iAalg);
+                return (KErrGeneral);
+                }
+            }
+        else if (iToken.Compare(_L("max_auth_bits")) == 0)
+            {
+            err = Val(aSpec.iSpec.iAalgLen, EDecimal);
+            if (err != KErrNone)
+                {
+                Error(_L("invalid auth alg length %d"), aSpec.iSpec.iAalgLen);
+                return (KErrGeneral);
+                }
+            }
+        else if ((iToken.Compare(_L("identity")) == 0) ||
+                 (iToken.Compare(_L("identity_remote")) == 0))
+            {
+            if (aSpec.iRemoteIdentity)
+                {
+                Error(_L("duplicate remote identity"));
+                err = KErrGeneral;
+                }
+            else if ((val = NextToken()) == token_string)
+                {
+                aSpec.iRemoteIdentity = HBufC8::NewL(iToken.Length() + 1);
+                aSpec.iRemoteIdentity->Des().Copy(iToken);
+                }
+            else
+                {
+                Error(_L("invalid remote identity value"));
+                err = KErrGeneral;
+                }
+            }
+        else if (iToken.Compare(_L("identity_local")) == 0)
+            {
+            if (aSpec.iLocalIdentity)
+                {
+                Error(_L("duplicate local identity"));
+                err = KErrGeneral;
+                }
+            else if ((val = NextToken()) == token_string)
+                {
+                aSpec.iLocalIdentity = HBufC8::NewL(iToken.Length() + 1);
+                aSpec.iLocalIdentity->Des().Copy(iToken);
+                }
+            else
+                {
+                Error(_L("invalid local identity value"));
+                err = KErrGeneral;
+                }
+            }
+        else if (iToken.Compare(_L("pfs")) == 0)
+            {
+            aSpec.iSpec.iPfs = 1;
+            }
+        else if (iToken.Compare(_L("connid_specific")) == 0)
+            {
+            // For backward compatibility
+            aSpec.iSpec.iMatchProtocol = 1;
+            aSpec.iSpec.iMatchRemotePort = 1;
+            aSpec.iSpec.iMatchLocalPort = 1;
+            }
+        else if (iToken.Compare(_L("protocol_specific")) == 0)
+            {
+            aSpec.iSpec.iMatchProtocol = 1;
+            }
+        else if ((iToken.Compare(_L("src_port_specific")) == 0)
+                 || (iToken.Compare(_L("local_port_specific")) == 0))
+            {
+            aSpec.iSpec.iMatchLocalPort = 1;
+            }
+        else if ((iToken.Compare(_L("dst_port_specific")) == 0)
+                 || (iToken.Compare(_L("remote_port_specific")) == 0))
+            {
+            aSpec.iSpec.iMatchRemotePort = 1;
+            }
+        else if (iToken.Compare(_L("proxy_specific")) == 0)
+            {
+            aSpec.iSpec.iMatchProxy = 1;
+            }
+        else if (iToken.Compare(_L("src_specific")) == 0)
+            {
+            aSpec.iSpec.iMatchSrc = 1;
+            }
+        else if (iToken.Compare(_L("local_specific")) == 0)
+            {
+            aSpec.iSpec.iMatchLocal = 1;
+            }
+        else if (iToken.Compare(_L("remote_specific")) == 0)
+            {
+            aSpec.iSpec.iMatchRemote = 1;
+            }
+        else if (iToken.Compare(_L("replay_win_len")) == 0)
+            {
+            err = Val(aSpec.iSpec.iReplayWindowLength, EDecimal);
+            }
+        else if (iToken.Compare(_L("hard_lifetime_allocations")) == 0)
+            {
+            err = Val(aSpec.iSpec.iHard.sadb_lifetime_allocations, EDecimal);
+            }
+        else if (iToken.Compare(_L("hard_lifetime_bytes")) == 0)
+            {
+            err = Val(aSpec.iSpec.iHard.sadb_lifetime_bytes, EDecimal);
+            }
+        else if (iToken.Compare(_L("hard_lifetime_addtime")) == 0)
+            {
+            err = Val(aSpec.iSpec.iHard.sadb_lifetime_addtime, EDecimal);
+            }
+        else if (iToken.Compare(_L("hard_lifetime_usetime")) == 0)
+            {
+            err = Val(aSpec.iSpec.iHard.sadb_lifetime_usetime, EDecimal);
+            }
+        else if (iToken.Compare(_L("soft_lifetime_allocations")) == 0)
+            {
+            err = Val(aSpec.iSpec.iSoft.sadb_lifetime_allocations, EDecimal);
+            }
+        else if (iToken.Compare(_L("soft_lifetime_bytes")) == 0)
+            {
+            err = Val(aSpec.iSpec.iSoft.sadb_lifetime_bytes, EDecimal);
+            }
+        else if (iToken.Compare(_L("soft_lifetime_addtime")) == 0)
+            {
+            err = Val(aSpec.iSpec.iSoft.sadb_lifetime_addtime, EDecimal);
+            }
+        else if (iToken.Compare(_L("soft_lifetime_usetime")) == 0)
+            {
+            err = Val(aSpec.iSpec.iSoft.sadb_lifetime_usetime, EDecimal);
+            }
+        else
+            {
+            Error(_L("invalid keyword"));
+            return (KErrGeneral);
+            }
+        if (err != KErrNone)
+            {
+            Error(_L("invalid numeric value"));
+            return (err);
+            }
+        }
+
+    if (val != token_brace_right)
+        {
+        Error(_L("right brace not found"));
+        return (KErrGeneral);
+        }
+    else if (sa_type_defined < 1)
+        {
+        Error(_L("sa type not defined for sa"));
+        return (KErrGeneral);
+        }
+    else if (sa_type_defined > 1)
+        {
+        Error(_L("sa type defined times for sa"));
+        return (KErrGeneral);
+        }
+    else if ((aSpec.iSpec.iType == SADB_SATYPE_AH) && !aSpec.iSpec.iAalg)
+        {
+        Error(_L("auth alg not defined for sa"));
+        return (KErrGeneral);
+        }
+    else if ((aSpec.iSpec.iType == SADB_SATYPE_ESP) && !aSpec.iSpec.iEalg)
+        {
+        Error(_L("encrypt alg not defined for sa"));
+        return (KErrGeneral);
+        }
+    else if ((aSpec.iSpec.iType == SADB_SATYPE_UNSPEC) &&
+             (aSpec.iSpec.iEalg || aSpec.iSpec.iAalg))
+        {
+        Error(_L("null SA cannot have any algorithms"));
+        return (KErrGeneral);
+        }
+
+    return (KErrNone);
+    }
+
+TInt
+TPolicyParser::parse_sa_specL(CSecurityPolicy* aSp)
+    {
+    LOG_("TPolicyParser::parse_sa_specL()\n");
+    TInt err(KErrNone);
+    CPolicySpec* spec(NULL);
+
+    if (NextToken() != token_string)
+        {
+        Error(_L("Syntax error"));
+        err = KErrGeneral;
+        }
+    else
+        {
+        spec = CPolicySpec::NewL(iToken);
+        aSp->Add(spec);
+
+        if (NextToken() != token_equal || NextToken() != token_brace_left)
+            {
+            Error(_L("Syntax error"));
+            err = KErrGeneral;
+            }
+        else
+            {
+            err = parse_sa_spec_paramsL(*spec);
+            }
+        }
+
+    return (err);
+    }
+
+TInt
+TPolicyParser::parse_sa_spec_listL(TSecpolBundle& aBundle,
+                                   CSecurityPolicy* aSp, TInt& aFQDNCount)
+    {
+    LOG_("TPolicyParser::parse_sa_spec_listL()\n");
+    CSecpolBundleItem* item(NULL);
+    CPolicySpec* spec(NULL);
+    token_type val;
+    TInt err(KErrNone);
+
+    while ((val = NextToken()) == token_string)
+        {
+        // Find the SA transform specification from the given policy
+        HBufC8 * hbuf = HBufC8::NewL(iToken.Length());
+        hbuf->Des().Copy(iToken);
+        spec = aSp->FindSpec(hbuf->Des());
+        delete hbuf;
+        hbuf = NULL;
+        
+        // A temporary(?) special kludge: if the keyword is 'tunnel'
+        // assume this is a plain tunnel specification, without any
+        // IPsec processing
+        
+        // NOTE: 
+        //  This works only when the SA specification name is not 'tunnel
+        //  ('tunnel' should be illegal name for SA specification to
+        //   avoid confusion)
+        if (!spec && iToken.Compare(_L("tunnel")))
+            {
+            Error(_L("sa or plain tunnel not defined"));
+            err = KErrGeneral;
+            break;
+            }
+
+        // Allocate memory for new bundle item
+        item = new (ELeave) CSecpolBundleItem;
+        CleanupStack::PushL(item);
+
+        // Init bundle item by using the SA transform template found        
+        item->iSpec = spec;
+        
+        // Read next token
+        val = NextToken();
+        
+        // Check that '(' found
+        if (val != token_par_left)
+            {
+            // Remove bundle item from the CleanupStack and set error code
+            CleanupStack::PopAndDestroy();
+            Error(_L("missing left parenthesis"));
+            err = KErrGeneral;
+            break;
+            }
+
+        // Read next token
+        val = NextToken();
+        
+        // Check if tunnel specification is set
+        if (val == token_string)
+            {
+            // Tunnel entry found so determine if name or plain address
+            if (aSp->SearchForEPNameL(iToken) == KErrNone)
+                {
+                // Tunnel name is set so copy it
+                item->iTunnelEpName = HBufC8::NewL(iToken.Length());
+                item->iTunnelEpName->Des().Copy(iToken);
+                }
+            else
+                {
+                // Try to instantiate IP address -- if not possible,
+                // consider the entry to represent an FQDN address,
+                // which needs to be looked up via DNS later on.
+                LOG_1("Found tunnel address: '%S'\n", &iToken);
+                err = item->iTunnel.Input(iToken);
+                if (err)
+                    {
+                    LOG_("Tunnel address invalid IP, assuming FQDN\n");
+                    item->iTunnelEpFQDN = iToken.AllocL();
+                    err = KErrNone;
+                    aFQDNCount++;
+                    }
+                }
+
+            LOG_("Parser proceeding to next token...\n");
+            // Read next token
+            val = NextToken();
+            }
+        
+        // Check that ')' terminates the definition correctly    
+        if (val != token_par_right)
+            {
+            // Remove bundle item from the CleanupStack and set error code
+            LOG_("Error: Closing parenthesis missing in ipsec policy section\n");
+            CleanupStack::PopAndDestroy();
+            Error(_L("missing right parenthesis"));
+            err = KErrGeneral;
+            break;
+            }
+
+        LOG_("Adding bundle to the list\n");
+        // Remove bundle item from the CleanupStack and add it into the list
+        CleanupStack::Pop();
+        aBundle.AddLast(*item);
+        }
+
+    // Check that terminating '}' is found
+    if (!err && val != token_brace_right)
+        {
+        LOG_("Error, missing right brace\n");
+        Error(_L("missing right brace"));
+        err = KErrGeneral;
+        }
+
+    LOG_1("Exiting, with error code %d\n", err);
+
+    return (err);
+    }
+
+TInt
+TPolicyParser::parse_ip_addr_and_maskL(
+    TInetAddr& addr,
+    TInetAddr& mask,
+    HBufC8*& aSelEpName,
+    HBufC8*& aMaskEpName,
+    CSecurityPolicy* aSecPol)
+    {
+    LOG_("TPolicyParser::parse_ip_addr_and_maskL()\n");
+    TInt err(KErrNone);
+    if (NextToken() != token_string)
+        {
+        Error(_L("ip address not found"));
+        return (KErrGeneral);
+        }
+
+    if (aSecPol->SearchForEPNameL(iToken) == KErrNone)
+        {
+        aSelEpName = HBufC8::NewL(iToken.Length());
+        aSelEpName->Des().Copy(iToken);
+        }
+    else
+        {
+        err = addr.Input(iToken);
+        if (err != 0)
+            {
+            Error(_L("invalid ip address "));
+            return (err);
+            }
+        }
+
+    if (NextToken() != token_string)
+        {
+        Error(_L("address mask not found"));
+        return (KErrGeneral);
+        }
+
+    if (aSecPol->SearchForEPNameL(iToken) == KErrNone)
+        {
+        aMaskEpName = HBufC8::NewL(iToken.Length());
+        aMaskEpName->Des().Copy(iToken);
+        }
+    else
+        {
+        err = mask.Input(iToken);
+        if (err != 0)
+            {
+            Error(_L("invalid address mask "));
+            return (err);
+            }
+        }
+
+    return (KErrNone);
+    }
+
+////////////////////////////////////////////////////////////
+// Parse the endpoint name entry
+////////////////////////////////////////////////////////////
+//
+TInt
+TPolicyParser::parse_ep_specL(CSecurityPolicy* aSp)
+    {
+    LOG_("TPolicyParser::parse_ep_specL()\n");
+    TInt err(KErrNone);
+    CPolicySpec* spec(NULL);
+
+    if (NextToken() != token_string)
+        {
+        Error(_L("Syntax error"));
+        err = KErrGeneral;
+        }
+    else
+        {
+        spec = CPolicySpec::NewL(iToken, EPolSpecEP);
+        aSp->Add(spec);
+
+        if (NextToken() != token_equal || NextToken() != token_brace_left)
+            {
+            Error(_L("Syntax error"));
+            err = KErrGeneral;
+            }
+        else
+            {
+            err = parse_ep_spec_paramsL(*spec);
+            }
+        }
+
+    return (err);
+    }
+
+////////////////////////////////////////////////////////////
+// Parse the endpoint name parameters
+////////////////////////////////////////////////////////////
+TInt
+TPolicyParser::parse_ep_spec_paramsL(CPolicySpec &aSpec)
+    {
+    LOG_("TPolicyParser::parse_ep_spec_paramsL()\n");
+    TInt err(KErrNone);
+    token_type val;
+
+    while ((val = NextToken()) == token_string)
+        {
+        if (iToken.Compare(_L("?")) == 0)
+            {
+            aSpec.iEpSpec.iIsOptional = ETrue;
+            }
+        else
+            {
+            err = aSpec.iEpSpec.iEpAddr.Input(iToken);
+            if (err != 0)
+                {
+                Error(_L("invalid ip address "));
+                return (err);
+                }
+            }
+        }
+
+    if (val != token_brace_right)
+        {
+        Error(_L("right brace not found"));
+        err = KErrGeneral;
+        }
+
+    return (err);
+    }
+
+TInt
+TPolicyParser::parse_conn2saL(CSecurityPolicy* aSp)
+    {
+    LOG_("TPolicyParser::parse_conn2saL()\n");
+    CPolicySelector* csa(NULL);
+    TInt err(KErrNone);
+    token_type val;
+    TUint port(0);
+
+    TInt fqdnCount(0);
+    csa = CPolicySelector::NewL();
+    aSp->Add(csa);
+
+    do
+        {
+        if ((iToken.Compare(_L("dst")) == 0)
+            || (iToken.Compare(_L("remote")) == 0))
+            {
+            err = parse_ip_addr_and_maskL(csa->iRemote,
+                                          csa->iRemoteMask,
+                                          csa->iRemSelEpName,
+                                          csa->iRemMaskEpName,
+                                          aSp);
+            }
+        else if ((iToken.Compare(_L("src")) == 0)
+                 || (iToken.Compare(_L("local")) == 0))
+            {
+            err = parse_ip_addr_and_maskL(csa->iLocal,
+                                          csa->iLocalMask,
+                                          csa->iLocSelEpName,
+                                          csa->iLocMaskEpName,
+                                          aSp);
+            }
+        else if (iToken.Compare(_L("outbound")) == 0)
+            {
+            if (csa->iDirection != KPolicySelector_SYMMETRIC)
+                {
+                Error(_L("Only one inbound or outbound allowed"));
+                return (KErrGeneral);
+                }
+            csa->iDirection = KPolicySelector_OUTBOUND;
+            }
+        else if (iToken.Compare(_L("inbound")) == 0)
+            {
+            if (csa->iDirection != KPolicySelector_SYMMETRIC)
+                {
+                Error(_L("Only one inbound or outbound allowed"));
+                return (KErrGeneral);
+                }
+            csa->iDirection = KPolicySelector_INBOUND;
+            }
+        else if (iToken.Compare(_L("user_id")) == 0)
+            {
+            ;   // Needs to be examined, TIdentity? -- msa
+            }
+        else if (iToken.Compare(_L("protocol")) == 0)
+            {
+            err = Val(csa->iProtocol);
+            }
+        else if ((iToken.Compare(_L("src_port")) == 0) ||
+                 (iToken.Compare(_L("local_port")) == 0))
+            {
+            err = Val(port);
+            csa->iLocal.SetPort(port);
+            }
+        else if ((iToken.Compare(_L("dst_port")) == 0) ||
+                 (iToken.Compare(_L("remote_port")) == 0))
+            {
+            err = Val(port);
+            csa->iRemote.SetPort(port);
+            }
+        else if (iToken.Compare(_L("icmp_type")) == 0)
+            {
+            err = Val(csa->iIcmpType);
+            }
+        else if (iToken.Compare(_L("type")) == 0)
+            {
+            err = Val(csa->iType);
+            }
+        else if (iToken.Compare(_L("icmp_code")) == 0)
+            {
+            err = Val(csa->iIcmpCode);
+            }
+        else if (iToken.Compare(_L("if")) == 0)
+            {
+            if (NextToken() != token_string)
+                {
+                Error(_L("Invalid interface specifier"));
+                err = KErrGeneral;
+                }
+            csa->iInterface.Append(iToken);
+            csa->iDirection = KPolicySelector_INTERFACE;
+            }
+        else if (iToken.Compare(_L("scope:global")) == 0)
+            {
+            csa->iGlobalSelector = ETrue;
+            }
+        else if (iToken.Compare(_L("final")) == 0 )
+            {
+            csa->iIsFinal = ETrue;
+            }
+        else if (iToken.Compare(_L("merge")) == 0 )
+            {
+            csa->iIsMerge = ETrue;
+            }
+        else
+            {
+            Error(_L("invalid keyword "));
+            return (KErrGeneral);
+            }
+
+        if (err != KErrNone)
+            {
+            // iMsg already contains an error text
+            if (iMsg.Length() != 0)
+                {
+                return err;
+                }
+            Error(_L("Error = %d"), err);
+            return err;
+            }
+        }
+    while ((val = NextToken()) == token_string);
+
+    if (val != token_equal )
+        {
+        Error(_L("Syntax error"));
+        err = KErrGeneral;
+        }
+    else if (NextToken() == token_brace_left)
+        {
+        err = parse_sa_spec_listL(csa->iBundle, aSp, fqdnCount);
+        }
+    else if (iToken.Compare(_L("drop")) == 0)
+        {
+        csa->iDropAction = ETrue;
+        }
+    else
+        {
+        Error(_L("Syntax error"));
+        err = KErrGeneral;
+        }
+    
+    LOG_1("SA FQDN Count: %d\n", fqdnCount);
+    aSp->IncFQDNCount(fqdnCount);
+    return (err);
+    }
+
+//
+// Keys Parsing
+//
+EXPORT_C CKeysData::CKeysData()
+    {}
+
+EXPORT_C CKeysData::CKeysData(CKeysData* aKey)
+    {
+    sa_type = aKey->sa_type;
+    spi = aKey->spi;
+    encr_alg = aKey->encr_alg;
+    auth_alg = aKey->auth_alg;
+    direction = aKey->direction;
+    lifetime_bytes = aKey->lifetime_bytes;
+    lifetime_sec = aKey->lifetime_sec;
+    src_addr = aKey->src_addr;        // Include port
+    dst_addr = aKey->dst_addr;        // Include port
+    protocol = aKey->protocol;
+    auth_key = aKey->auth_key;
+    encr_key = aKey->encr_key;
+    }
+
+//
+//  CKeysDataArray
+//
+CKeysDataArray::CKeysDataArray(TInt aGranularity) :
+        CArrayFixFlat<class CKeysData *>(aGranularity)
+    {}
+
+EXPORT_C CKeysDataArray* CKeysDataArray::NewL(TInt aGranularity)
+    {
+    CKeysDataArray* self = new (ELeave) CKeysDataArray(aGranularity);
+    self->Construct(aGranularity);
+    return self;
+    }
+
+EXPORT_C void CKeysDataArray::Construct(TInt /* aGranularity */)
+    {}
+
+CKeysDataArray::CKeysDataArray(CKeysDataArray* aData) :
+        CArrayFixFlat<class CKeysData *>(aData->Count())
+    {}
+
+EXPORT_C CKeysDataArray* CKeysDataArray::NewL(CKeysDataArray* aData)
+    {
+    CKeysDataArray* self = new (ELeave) CKeysDataArray(aData);
+    CleanupStack::PushL(self);
+    self->ConstructL(aData);
+    CleanupStack::Pop();
+    return self;
+    }
+
+EXPORT_C void CKeysDataArray::ConstructL(CKeysDataArray* aData)
+    {
+    CopyL(aData);
+    }
+
+EXPORT_C CKeysDataArray::~CKeysDataArray()
+    {
+    Empty();
+    }
+
+// Construct this from the data in aData
+EXPORT_C void CKeysDataArray::CopyL(CKeysDataArray* aData)
+    {
+    CKeysData* key_data(NULL);
+    for (TInt i = 0; i < aData->Count(); i++)
+        {
+        key_data = new (ELeave) CKeysData(aData->At(i));
+        CleanupStack::PushL(key_data);
+        AppendL(key_data);
+        CleanupStack::Pop();
+        }
+    }
+
+EXPORT_C void
+CKeysDataArray::Empty()
+    {
+    for (TInt i = 0; i < Count(); i++)
+        {
+        delete At(i);
+        }
+
+    Reset();
+    }
+
+//
+// TKeyParser
+//
+EXPORT_C
+TKeyParser::TKeyParser(const TDesC &aStr) : TLex(aStr)
+    {
+    iFirst = 1;
+    }
+
+EXPORT_C TInt
+TKeyParser::ParseL(CKeysDataArray *aKeys)
+    {
+    LOG_("TKeyParser::ParseL()\n");
+    TInt err(KErrNone);
+
+    while (!err)
+        {
+        // Skip until first token in line
+        while (iFirst == 0)
+            NextToken();
+
+        if (iFirst < 0)
+            break;
+
+        NextToken();
+        if ((iToken.Compare(_L("pfkey_add")) == 0))
+            {
+            TInt val(0);
+            CKeysData* keyData(NULL);
+            for (int i = 0; !err && iFirst == 0; ++i)
+                {
+                switch (i)
+                    {
+                        // sa type: 1=AH, 2=ESP
+                    case 0:
+                        keyData = new (ELeave) CKeysData;
+                        err = Val(val);
+                        if (val == 1)
+                            keyData->sa_type = SADB_SATYPE_AH;
+                        else if (val == 2)
+                            keyData->sa_type = SADB_SATYPE_ESP;
+                        else
+                            err = KErrGeneral;
+                        break;
+
+                        // spi: 1..MAX_UINT32
+                    case 1:
+                        err = Val(keyData->spi);
+                        break;
+
+                        // Pass encryption alg numbers as is
+                    case 2:
+                        err = Val(keyData->encr_alg, EDecimal);
+                        break;
+
+                        // Pass authentication alg numbers as is
+                    case 3:
+                        err = Val(keyData->auth_alg, EDecimal);
+                        break;
+
+                        // direction: 4 = inbound, 8 = outbound                        
+                    case 4:
+                        err = Val(keyData->direction);
+                        // Not used, direction is implicit by the src/dst pair
+                        if (keyData->direction & ~(PFKEY_INI_INBOUND 
+                                                   | PFKEY_INI_OUTBOUND))
+                            err = KErrGeneral;
+                        break;
+
+                        // lifetime as bytes: 0 = not used, 
+                        //                    1..MAX_UINT32=max sa lifetime                        
+                    case 5:     
+                        err = Val(keyData->lifetime_bytes);
+                        break;
+
+                        // lifetime as seconds: 0 = not used, 
+                        //                      1..MAX_UINT32=max sa lifetime
+                    case 6:     
+                        err = Val(keyData->lifetime_sec);
+                        break;
+
+                        // src ip addr: in a.b.c.d format                        
+                    case 7:     
+                        NextToken();
+                        err = keyData->src_addr.Input(iToken);
+                        break;
+
+                        // dst ip addr: in a.b.c.d format
+                    case 8:     
+                        NextToken();
+                        err = keyData->dst_addr.Input(iToken);
+                        break;
+
+                        // protocol: 0 = sa NOT protocol specific,                        
+                        //           1 = ICMP, 4 = IPIP, 6 = TCP, 17 = UDP
+                    case 9:     
+                        err = Val(val);
+                        keyData->protocol = (TUint8)val;
+                        break;
+
+                        // local port: 0 = sa NOT src port specific,
+                        //             1..MAX_UINT16 = src port for which sa 
+                        //             dedicated
+                    case 10:    
+                        err = Val(val);
+                        keyData->src_addr.SetPort(val);
+                        break;
+
+                        // remote port: 0 = sa NOT dst port specific,
+                        //              1..MAX_UINT16 = dst port for which 
+                        //              sa dedicated
+                    case 11:    
+                        err = Val(val);
+                        keyData->dst_addr.SetPort(val);
+                        break;
+
+                        // authentication key:  as hex string WITHOUT leading 0x,
+                        //               two hex digits for every 8 bits of key,
+                        //               HMAC-MD5: 128 bit = 16 byte key,
+                        //               HMAC-SHA1: 160 bit = 20 byte key
+                    case 12:
+                        NextToken();
+                        if (iToken != _L("0"))
+                            {
+                            // 0 is No key assigned    
+                            keyData->auth_key.Copy(iToken);
+                            }
+                        break;
+
+                        // encryption key: as hex string WITHOUT leading 0x,                        
+                        //             two hex digits for every 8 bits of key,
+                        //             DES-CBC: 64 bit = 8 byte key,
+                        //             DES-EDE3-CBC: 192 bit = 24 byte key
+                    case 13:    
+                        NextToken();
+                        if (iToken != _L("0"))    //0 is No key assigned
+                            keyData->encr_key.Copy(iToken);
+                        break;
+
+                    default:
+                        NextToken();
+                        err = KErrKeyParser;
+                        break;
+                    } // switch
+                SkipSpaceAndMark();
+                } // for
+
+            if (err == KErrNone && keyData)
+                {
+                CleanupStack::PushL(keyData);
+                aKeys->AppendL(keyData);
+                CleanupStack::Pop();
+                }
+            else
+                {
+                delete keyData;
+                keyData = NULL;
+                }
+            }   // if
+        }   // while
+
+    return (err);
+    }
+
+EXPORT_C TInt 
+TKeyParser::Write(CKeysDataArray *aKeys, RFile &aFile)
+    {
+    LOG_("TKeyParser::Write()\n");
+    TBuf8<500> text;
+    TInt err(KErrNone);
+    TInt count = aKeys->Count();
+    for (TInt i = 0; i < count ; i++)
+        {
+        TextPFKey(aKeys->At(i), text);
+        err = aFile.Write(text);
+        if (err != KErrNone)
+            break;
+        }
+    return (err);
+    }
+
+void 
+TKeyParser::TextPFKey(CKeysData *aKey, TDes8 &aElem)
+    {
+    TBuf<39> addr;
+    TBuf8<39> addr8;
+
+    aElem.Format(_L8("pfkey_add "));
+
+    if (aKey->sa_type == SADB_SATYPE_AH)
+        aElem.AppendFormat(_L8("%d "), 1);
+    else
+        aElem.AppendFormat(_L8("%d "), 2);
+
+    aElem.AppendFormat(_L8("%d "), aKey->spi);
+
+    // Algorithms
+    aElem.AppendFormat(_L8("%d "), aKey->encr_alg);
+    aElem.AppendFormat(_L8("%d "), aKey->auth_alg);
+
+
+    aElem.AppendFormat(_L8("%d "), aKey->direction);
+
+    aElem.AppendFormat(_L8("%d "), aKey->lifetime_bytes);
+    aElem.AppendFormat(_L8("%d "), aKey->lifetime_sec);
+
+    // Addresses
+    aKey->src_addr.OutputWithScope(addr);
+
+    addr8.Copy(addr);
+    aElem.AppendFormat(addr8);
+    aElem.AppendFormat(_L8(" "));
+    aKey->dst_addr.OutputWithScope(addr);
+
+    addr8.Copy(addr);
+    aElem.AppendFormat(addr8);
+    aElem.AppendFormat(_L8(" "));
+    aElem.AppendFormat(_L8("%d "), aKey->protocol);
+
+    // Ports
+    aElem.AppendFormat(_L8("%d "), aKey->src_addr.Port());
+    aElem.AppendFormat(_L8("%d "), aKey->dst_addr.Port());
+
+    // Keys
+    if (aKey->auth_key.Length() != 0)
+        aElem.Append(aKey->auth_key);
+    else
+        aElem.Append(_L8("0"));
+
+    aElem.Append(_L8(" "));
+
+    if (aKey->encr_key.Length() != 0)
+        aElem.Append(aKey->encr_key);
+    else
+        aElem.Append(_L8("0"));
+
+    aElem.Append(_L8("\n"));
+    }
+
+//
+// Skip white space and mark, including comments!
+//
+TInt 
+TKeyParser::SkipSpaceAndMark()
+    {
+    TChar ch;
+    TInt comment = 0;
+    TInt newline = 0;
+
+    while (!Eos())
+        {
+        ch = Get();
+        if (ch == '\n')
+            {
+            comment = 0;
+            newline = 1;
+            }
+        else if (comment || ch == '#')
+            comment = 1;
+        else if (!ch.IsSpace())
+            {
+            UnGet();
+            break;
+            }
+        }
+    Mark();
+    return newline;
+    }
+
+//
+// Extract Next token and return
+//
+void 
+TKeyParser::NextToken()
+    {
+    if (SkipSpaceAndMark())
+        iFirst = 1;     // New line!
+
+    if (Eos())
+        {
+        iFirst = -1;
+        return ;
+        }
+
+    while (!Eos())
+        {
+        TChar ch = Peek();
+        if (ch == '#' || ch.IsSpace())
+            break;
+        Inc();
+        }
+    iToken.Set(MarkedToken());
+    iFirst = SkipSpaceAndMark();
+    }
+
+TUint8 
+TKeyParser::HexVal(TUint8 c)
+    {
+    if (c >= 'a' && c <= 'f')
+        return (TUint8)(c - 'a' + 10);
+    else if (c >= 'A' && c <= 'F')
+        return (TUint8)(c - 'A');
+    else if (c >= '0' && c <= '9')
+        return (TUint8)(c - '0');
+    else
+        return 0;
+    }
+
+TPtrC8 
+TKeyParser::DeHex(const TDesC &aStr)
+    {
+    const TUint8* s = (TUint8 *)aStr.Ptr();
+    TUint8* d = (TUint8 *)iHex.Ptr();
+    TInt i = aStr.Length();
+    TUint8 d1 = 0;
+    TUint8 d2 = 0;
+
+    while (i > 0)
+        {
+        d1 = TKeyParser::HexVal(*s++);
+        d2 = i > 1 ? TKeyParser::HexVal(*s++) : (TUint8)0;
+        i -= 2;
+        *d++ = (TUint8)(d1 * 16 + d2);
+        }
+
+    iHex.SetLength(d - iHex.Ptr());
+    return iHex;
+    }
+
+//
+// Parses an security configuration file
+// 
+EXPORT_C 
+TIpSecParser::TIpSecParser(const TDesC &aDes) : TLex(aDes)
+    {
+    LOG_("VPN ipsec policy parser instantiated\n");
+    }
+
+EXPORT_C TInt 
+TIpSecParser::ParseL(CIpSecurityPiece *aPiece_data)
+    {
+    LOG_("TIpSecParser::ParseL()\n");
+    return DoParseL(aPiece_data, ETrue);
+    }
+
+EXPORT_C TInt 
+TIpSecParser::ParseAndIgnoreIKEL(CIpSecurityPiece *aPiece_data)
+    {
+    LOG_("TIpSecParser::ParseAndIgnoreIKEL()\n");
+    return DoParseL(aPiece_data, EFalse);
+    }
+
+TInt 
+TIpSecParser::DoParseL(CIpSecurityPiece *aPiece_data,
+                            TBool /* aIncludeIKE */)
+    {
+    LOG_("TIpSecParser::DoParseL()\n");
+    TPtrC token(NULL, 0);
+    TInt ret(0);
+
+    if (!CheckVersion())
+        return KErrNotSupported;    // Invalid file or version
+
+    while (!Eos())
+        {
+        token.Set(NextToken());
+        if (token.Compare(_L("[INFO]")) == 0)
+            {
+            ParseInfoL(aPiece_data);
+            }
+        else if (token.Compare(_L("[POLICY]")) == 0)
+            {
+            ret = ParsePoliciesL(aPiece_data);
+            if (ret != KErrNone)
+                return ret;
+            }
+        else if (token.Compare(_L("[KEYS]")) == 0)
+            {
+            ret = ParseKeysL(aPiece_data->Keys());
+            if (ret != KErrNone)
+                return ret;
+            }
+        else
+            {
+            // Unknown Tag Ignored
+            NextTag();
+            }
+        }
+
+    return (KErrNone);
+    }
+
+TBool 
+TIpSecParser::CheckVersion()
+    {
+    TPtrC token(NULL, 0);
+    TLex version_num;
+
+    token.Set(NextToken());
+    if (token.Compare(_L("SECURITY_FILE_VERSION:")) == 0)
+        {
+        version_num = NextToken();
+        if (version_num.Val(iVersion) != KErrNone)
+            return EFalse;
+        if ((iVersion < FIRST_SEC_PARSER_VERSION) ||
+            (iVersion > SEC_PARSER_VERSION))
+            return EFalse;
+        }
+    else
+        return EFalse;
+
+    return ETrue;
+
+    }
+
+void 
+TIpSecParser::ParseInfoL(CIpSecurityPiece *aPiece_data)
+    {
+    HBufC *buf = HBufC::NewL(MAX_INFO_SIZE);
+    TPtr ptr = buf->Des();
+    TChar ch = Get();
+    TInt i(0);
+
+    CleanupStack::PushL(buf);
+
+    ch = Get();
+    while (((ch == ' ') || (ch == '\n')) && (!Eos()))
+        {
+        ch = Get();
+        }
+
+    while ((ch != '[') && (!Eos()) && i < MAX_INFO_SIZE)
+        {
+        ptr.Append(ch);
+        i++;
+        ch = Get();
+        }
+
+    if (i == MAX_INFO_SIZE) //The rest is ignored
+        {
+        ch = Get();
+        while ( (ch != '[') && (!Eos()) )
+            ch = Get();
+        }
+
+    if (ch == '[')
+        {
+        UnGet();    // the '['
+        if (ptr.Length() > 0)   //If empty no \n
+            ptr.SetLength(ptr.Length() - 1);    //eliminates the \n at the end
+        }
+
+    aPiece_data->SetInfoL(ptr);
+    CleanupStack::PopAndDestroy();
+    }
+
+TInt 
+TIpSecParser::ParsePoliciesL(CIpSecurityPiece *aPieceData)
+    {
+    LOG_("TIpSecParser::ParsePoliciesL()\n");
+    TInt err;
+    TInt pos = Remainder().Find(_L("SECURITY_FILE_VERSION:"));
+    if (pos == KErrNotFound)
+        {
+        pos = Remainder().Find(_L("["));   //The segment is until the next tag or Eos()
+        }
+    if (pos != KErrNotFound)
+        {
+        TPtr pol_ptr((TUint16 *)Remainder().Ptr(), pos, pos);    //Until the next section
+        TPolicyParser parser(pol_ptr);
+        err = parser.ParseL(aPieceData);
+        Assign(Remainder().Ptr() + pos);    //rest of the text to parse
+        }
+    else
+        {
+        TPolicyParser parser(Remainder());
+        err = parser.ParseL(aPieceData);
+        }
+    return (err);
+    }
+
+TInt 
+TIpSecParser::ParseKeysL(CKeysDataArray *aKeys)
+    {
+    TInt err;
+    //The segment is until the next tag or Eos()
+    TInt pos = Remainder().Find(_L("["));
+    if (pos != KErrNotFound)
+        {
+        // Until the next section
+        TPtr key_ptr((TUint16 *)Remainder().Ptr(), pos, pos);
+        TKeyParser parser(key_ptr);
+        err = parser.ParseL(aKeys);
+
+        // Rest of the text to parse
+        Assign(Remainder().Ptr() + pos);
+        }
+    else
+        {
+        // No more tags
+        TKeyParser parser(Remainder());
+        err = parser.ParseL(aKeys);
+        }
+
+    return (err);
+    }
+
+void 
+TIpSecParser::NextTag()
+    {
+    while (!Eos())
+        if (Get() == '[' )
+            {
+            // Next tag found
+            UnGet();
+            return ;
+            }
+    }
+
+// Puts the security file data into string format to be saved to the
+// caller's buffer.
+EXPORT_C TInt 
+TIpSecParser::Write(CIpSecurityPiece* aPiece_data,
+                    HBufC8*& aPolBfr)
+    {
+    LOG_("TIpSecParser::Write()\n");
+    TInt err(KErrNone);
+
+    err = WriteVersion(aPolBfr);
+    if (err != KErrNone)
+        return err;
+
+    err = WriteInfo(aPiece_data, aPolBfr);
+    if (err != KErrNone)
+        return err;
+
+    err = WritePolicies(aPiece_data, aPolBfr);
+    if (err != KErrNone)
+        return err;
+
+    return (err);
+    }
+
+TInt 
+TIpSecParser::WriteVersion(HBufC8*& aPolBfr)
+    {
+    TBuf8<32> buf;
+    buf.Format(_L8("SECURITY_FILE_VERSION: %d\n"), SEC_PARSER_VERSION);
+    return TPolicyParser::BufferAppend(aPolBfr, buf);
+    }
+
+TInt 
+TIpSecParser::WriteInfo(CIpSecurityPiece *aPiece_data, HBufC8*& aPolBfr)
+    {
+    TInt err;
+
+    TBuf8<MAX_INFO_SIZE> buf = _L8("[INFO]\n");
+    err = TPolicyParser::BufferAppend(aPolBfr, buf);
+    if (err != KErrNone)
+        return err;
+
+    buf.Copy(aPiece_data->Info()->Des());
+    err = TPolicyParser::BufferAppend(aPolBfr, buf);
+    if (err != KErrNone)
+        return err;
+    return TPolicyParser::BufferAppend(aPolBfr, (_L8("\n")));
+
+    }
+
+TInt 
+TIpSecParser::WritePolicies(CIpSecurityPiece *aPiece_data, HBufC8*& aPolBfr)
+    {
+    LOG_("TIpSecParser::WritePolicies()\n");
+    TBuf8<10> buf = _L8("[POLICY]\n");
+    TInt err = TPolicyParser::BufferAppend(aPolBfr, buf);
+    if (err != KErrNone)
+        return err;
+    return TPolicyParser::Write(aPiece_data->Policies(), aPolBfr);
+    }
+
+//
+// CIpSecurityPiece
+//
+EXPORT_C void 
+CIpSecurityPiece::ConstructL(TInt aSize)
+    {
+    LOG_("CIpSecurityPiece::ConstructL()\n");
+    iInfo = HBufC::NewL(aSize);
+    iPolicies = new (ELeave) CSecurityPolicy();
+    iPolicies->ConstructL();
+    iKeys = CKeysDataArray::NewL(1);
+    }
+
+EXPORT_C void 
+CIpSecurityPiece::SetInfoL(const TDesC &aDes)
+    {
+    LOG_("CIpSecurityPiece::SetInfoL()\n");
+    if (aDes.Length() > iInfo->Des().MaxLength())
+        {
+        // ReAllocs if needed
+        iInfo = iInfo->ReAllocL(aDes.Length());
+        }
+
+    iInfo->Des().Copy(aDes);
+    }
+
+EXPORT_C 
+CIpSecurityPiece::~CIpSecurityPiece()
+    {
+    LOG_("CIpSecurityPiece::~CIpSecurityPiece()\n");
+    delete iInfo;
+    delete iPolicies;
+    delete iKeys;
+    delete iPolicyList;
+    }
+
+EXPORT_C CSecPolBundleList* CIpSecurityPiece::FQDNAddressListL()
+    {
+    LOG_("CIpSecurityPiece::GetFQDNAddressListL() entry\n");
+    LOG_("Deleting policy list\n");
+    if (iPolicyList) 
+        {
+        delete iPolicyList;
+        iPolicyList = NULL;
+        }
+    LOG_("Querying DNS task count\n");
+    TInt fqdnCount = iPolicies->FQDNCount();
+
+    LOG_1("DNS Task Count: %d\n", fqdnCount);
+    
+    if (fqdnCount > 0) 
+        {
+
+        LOG_("Instantiating new policy list\n");
+        iPolicyList = new (ELeave) CSecPolBundleList(fqdnCount);
+
+        LOG_("Querying DNS tasks\n");
+
+        if (iPolicies != NULL) 
+            {
+            iPolicies->GetFQDNAddressListL(*iPolicyList);
+            }
+        else 
+            {
+            LOG_("No ipsec policies!\n");
+            }
+        LOG_("CIpSecurityPiece::GetFQDNAddressListL() exit\n");
+        }
+    return iPolicyList;
+    }