--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networksecurity/ipsec/ipsec6/src/spdb.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,1510 @@
+// Copyright (c) 2005-2009 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:
+// spdb.cpp - IPv6/IPv4 IPsec Security Policy Database (SPD)
+// Implementation of the IPsec Security Policy Database (SPD)
+//
+
+
+
+/**
+ @file spdb.cpp
+*/
+#include "epdb.h"
+#include "spdb.h"
+#include <networking/pfkeyv2.h>
+#include "sa_spec.h"
+#include <networking/ipsecerr.h>
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+#include <e32std.h>
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+#ifndef OLD_SELECTOR_ORDERING
+/** @deprecated
+* The old syntax allowed total mixing of "filter" and "selector"
+* keywords. The new syntax requires the filter keywords (outbound,
+* inbound, merge, final, etc.) to precede any real selectors.
+* For backward compatibility, allow old deprecated ordering, if
+* OLD_SELECTOR_ORDERING is defined.
+*/
+#define OLD_SELECTOR_ORDERING 1
+#endif
+
+
+/**
+* Static keyword macro.
+*
+* Store all keywords as "plain ascii" (narrow, not UNICODE)
+*/
+#define KEYWORD(s) {(sizeof(s)-1), (const TText8 *)s}
+
+/**
+* Keyword number macro.
+*
+* Generate enum name for the keyword 's'.
+*/
+#define KEYENUM(s) E_ ## s
+
+
+
+
+
+
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+// CPropList
+CPropList::CPropList(TInt aGranularity) :
+ CArrayFixFlat<CSecurityProposalSpec *>(aGranularity)
+ {}
+
+ CPropList* CPropList::NewL(TInt aGranularity)
+ {
+ CPropList* self = new (ELeave) CPropList(aGranularity);
+ self->Construct(aGranularity);
+ return self;
+ }
+
+ void CPropList::Construct(TInt /* aGranularity */)
+ {}
+
+CPropList::CPropList(CPropList* aSAList) :
+ CArrayFixFlat<CSecurityProposalSpec *>(aSAList->Count())
+ {}
+
+CPropList* CPropList::NewL(CPropList* aSAList)
+ {
+ CPropList* self = new (ELeave) CPropList(aSAList);
+ CleanupStack::PushL(self);
+ self->ConstructL(aSAList);
+ CleanupStack::Pop();
+ return self;
+ }
+
+ void CPropList::ConstructL(CPropList* aSAList)
+ {
+ TInt count(aSAList->Count());
+ }
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+
+class TKeyword
+ /**
+ * The keyword definition.
+ */
+ {
+public:
+ TInt iLength; //< Length of the keyword
+ const TText8 *iWord; //< The keyword
+ };
+
+static TInt Lookup(const TKeyword *const aList, const TInt aLength, const TDesC &aToken)
+ /**
+ * Lookup a keyword from list.
+ *
+ * @param aList The list of keyword
+ * @param aLength The number of keywords in the list
+ * @param aToken The keyword to be looked for
+ *
+ * @return
+ * The index of the matched keyword, or aLength, if none matches.
+ */
+ {
+ const TInt token_length = aToken.Length();
+ for (TInt i = 0; i < aLength; i++)
+ {
+ const TKeyword &key = aList[i];
+ if (key.iLength == token_length)
+ {
+ // Use own matching loop (instead of Compare), because keywords
+ // are stored as 8-bit strings (to make them compact).
+ for (TInt k = token_length;;)
+ {
+ if (--k < 0)
+ return i; // Keyword matched!
+ if (key.iWord[k] != aToken[k])
+ break; // No Match!
+ }
+ }
+ }
+ return aLength;
+ }
+
+
+typedef enum
+ /**
+ * Tokens of the IPsec policy syntax.
+ */
+ {
+ token_string, //< Any string of non-white space and non-token characters.
+ token_question, //< Question mark: '?'
+ token_equal, //< Equal sign: '='
+ token_comma, //< Comma: ','
+ token_brace_left, //< Left brace: '{'
+ token_brace_right, //< Right brace: '}'
+ token_par_left, //< Left parens: '('
+ token_par_right, //< Right parens: ')'
+ token_eof //< End of policy string.
+ } token_type;
+
+class TParser : public TLex
+ /**
+ * Parser of the policy definition.
+ */
+ {
+public:
+ TParser(CSecurityPolicy *aSP, const TDesC &aPolicy, REndPoints &aEp);
+ void ParseL(TUint aStartOffset);
+private:
+ void ParseEndPointL();
+ void SetAddressOrEndPointL(RIpAddress &aAddr, TInt aMask, TInt aError);
+ void ParseAddressL(RIpAddress &aAddr, TInt aMask, TInt aError);
+ void ParseAddressAndMaskL(RIpAddress &aAddr, RIpAddress& aMask);
+ void ParseSecurityBundleL(RPolicyActions &aBundle, CTransportSelector *aTS);
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ void ParseAssociationParametersL(CPolicySpec *aSpec);
+#else
+ void ParseAssociationParametersL(TSecurityAssocSpec &aSpec);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ void ParseSelectorL(CPolicySelector *&aPs);
+ token_type TransportSelectorL(CTransportSelector *& aTS);
+ void ParseAssociationL();
+ TAlgorithmMap *ParseAlgorithmReferenceL(TInt anInsert);
+ TInt ParseAlgorithmMappingL(TAlgorithmClass aClass);
+ token_type NextToken();
+ void SkipSpaceAndMark();
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ token_type CheckProposalCloseAndMoreProposals(TInt &aPropBraces);
+ CSecurityProposalSpec* CreateProposalL(CPropList& aPropList);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ TPtrC iToken; //< The current token.
+ CSecurityPolicy *iSp; //< The result of the parsing operation, The new policy
+ REndPoints &iEp; //< The End Point collection to use for the named endpoints.
+ };
+
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+CSecurityProposalSpec* TParser::CreateProposalL(CPropList& aPropList)
+ {
+ CSecurityProposalSpec* prop = new(ELeave) CSecurityProposalSpec;
+ prop->iType = SADB_SATYPE_UNSPEC;
+ aPropList.AppendL(prop);
+ return prop;
+ }
+
+token_type TParser::CheckProposalCloseAndMoreProposals(TInt &aPropBraces)
+ {
+ token_type val;
+ val=NextToken();
+ if (val == token_brace_right )
+ {
+ if (--aPropBraces != -1)
+ return NextToken();
+ }
+ return val;
+ }
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+void TParser::SkipSpaceAndMark()
+ /**
+ * Skip white space and mark.
+ *
+ * Skip white space and comments. The '#' character
+ * starts a comment that continues to the end of the line.
+ * Syntactically, a comment is white space (and terminates
+ * token string.
+ *
+ * Set the mark on first character that is not white space.
+ */
+ {
+ TInt comment = 0;
+ while (!Eos())
+ {
+ const TChar ch = Get();
+ if (ch == '\n')
+ comment = 0;
+ else if (comment || ch == '#')
+ comment = 1;
+ else if (!ch.IsSpace())
+ {
+ UnGet();
+ break;
+ }
+ }
+ Mark();
+ }
+
+token_type TParser::NextToken()
+ /**
+ * Parse over the next token.
+ *
+ * Skip over white space and return the next token. The
+ * parsing point is after the returned token. Set the
+ * iToken to reference the returned token as a string.
+ *
+ * @return The token type
+ */
+ {
+ token_type val;
+
+ SkipSpaceAndMark();
+ if (Eos())
+ val = token_eof;
+ else
+ {
+ TChar 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 if (ch == '?')
+ val = token_question;
+ else
+ {
+ val = token_string;
+ while (!Eos())
+ {
+ ch = Peek();
+ if (ch == '{' || ch == '}' ||
+ ch == '(' || ch == ')' ||
+ ch == '=' || ch == '#' ||
+ ch == '?' || ch.IsSpace())
+ break;
+ Inc();
+ }
+ }
+ }
+ iToken.Set(MarkedToken());
+ SkipSpaceAndMark();
+ return val;
+ }
+
+TAlgorithmMap *TParser::ParseAlgorithmReferenceL(TInt aInsert)
+ /**
+ * Parse algorithm reference
+ * @code [ library '.' ] algorithm
+ * @endcode
+ *
+ * @param aInsert Create TAlgorithMap, if not found
+ * @return The algorithm map.
+ */
+ {
+ _LIT(K_null, "null");
+
+ if (NextToken() == token_string)
+ {
+ TInt dot = iToken.Locate('.');
+ const TPtrC lib = dot < 0 ? (TPtrC&)KNullDesC() : iToken.Left(dot);
+ TPtrC alg = dot < 0 ? iToken : iToken.Right(iToken.Length()-dot-1);
+ if (alg.Compare(K_null) == 0)
+ alg.Set(0,0); // 'null' is a special algorithm name!
+ TAlgorithmMap *map = iSp->FindAlg(lib, alg);
+ if (map == NULL && aInsert)
+ map = iSp->NewAlgL(lib, alg);
+ return map;
+ }
+ // Ás this is syntax error, should probably report something..
+ return NULL;
+ }
+
+
+TInt TParser::ParseAlgorithmMappingL(TAlgorithmClass aClass)
+ /**
+ * Parse algorithm mapping
+ * @code ParseAlgorithmReferenceL '(' id ',' bits [',' dummy]* ')'
+ * @endcode
+ *
+ * The library reference is followed by a list of numbers in
+ * parentheses. The kernel side only needs one or two (for digest)
+ * and rest are ignored (the other numbers may be used by the
+ * key management or configuration tools).
+ *
+ * @param aClass Algorithm type (cipher or digest).
+ * @return KErrNone if no errors.
+ */
+ {
+ TAlgorithmMap *map = ParseAlgorithmReferenceL(1);
+ if (map && NextToken() == token_par_left)
+ {
+ TInt i, n;
+ map->iClass = aClass;
+ for (i = 0;;++i)
+ {
+ const TInt error = Val(n);
+ if (error != KErrNone)
+ return error;
+ //
+ // Only the first two integers are used by the
+ // kernel IPSEC, pass other numbers silently.
+ //
+ if (i == 0)
+ map->iId = n;
+ else if (i == 1)
+ map->iBits = n;
+
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (map->iId == SADB_AALG_AES_XCBC_MAC)
+ {
+ map->iClass = EAlgorithmClass_Mac;
+ }
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ const TInt tok = NextToken();
+ if (tok == token_par_right)
+ break;
+ else if (tok != token_comma)
+ return KErrGeneral;
+ }
+ //
+ // At least one number (id) must be present
+ //
+ if (i == 0)
+ return KErrGeneral;
+ }
+ return KErrNone;
+ }
+
+
+void TParser::ParseEndPointL()
+ /**
+ * Parse Named End Point
+ * @code name '=' '{' [ '?' ] ip-address '}'
+ * @endcode
+ */
+ {
+ if (NextToken() != token_string)
+ User::Leave(EIpsec_PolicySpecName); // Endpoint name expeted!
+ // Allocate a slot for the new association specification
+
+ const TPtrC name(iToken);
+
+ if (NextToken() != token_equal ||
+ NextToken() != token_brace_left)
+ User::Leave(EIpsec_PolicySyntaxError);
+
+ TInt opt = 0;
+ token_type val = NextToken();
+ if (val == token_question)
+ {
+ opt = 1;
+ val = NextToken();
+ }
+ TIpAddress addr;
+ if (val == token_brace_right)
+ addr.SetAddressNone();
+ else
+ {
+ if (val != token_string || addr.SetAddress(iToken) != KErrNone)
+ User::Leave(EIpsec_PolicyIpAddressExpected);
+ if (NextToken() != token_brace_right)
+ User::Leave(EIpsec_PolicyCloseBraceExpected);
+ }
+
+ // Add RIpAddress handle to iEndPoints to keep the EP around
+ // as long as this policy is loaded (if EP is attached to some
+ // other objects, like SA, its life extends beyond the policy
+ // life).
+ const TInt index = iSp->iEndPoints.Count();
+ User::LeaveIfError(iSp->iEndPoints.Append(RIpAddress()));
+ User::LeaveIfError(iSp->iEndPoints[index].Open(iEp, name, addr, opt));
+ }
+
+
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+void TParser::ParseAssociationParametersL(CPolicySpec *aPolicySpec)
+#else
+void TParser::ParseAssociationParametersL(TSecurityAssocSpec &aSpec)
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ /**
+ * Parse a sequence of association parameters
+ * @code [ 'ah' | 'esp' | 'encrypt_alg' number | 'auth_alg' number |
+ * 'identity' string | 'identity_remote' string | 'identity_local' string |
+ * 'pfs' |
+ * 'protocol_specific' | 'local_port_specific' | 'remote_port_specific' |
+ * 'proxy_specific' | 'local_specific' | 'remote_specific' |
+ * 'src_specific' | 'replay_win_len' number |
+ * 'min_auth_bits' number | 'max_auth_bits' number |
+ * 'min_encrypt_bits' number | 'max_encrypt_bits' number |
+ * 'hard_lifetime_allocations' number | 'hard_lifetime_bytes' number |
+ * 'hard_lifetime_addtime' number | 'hard_lifetime_usetime' number |
+ * 'soft_lifetime_allocations' number | 'soft_lifetime_bytes' number |
+ * 'soft_lifetime_addtime' number | 'soft_lifetime_usetime' number | 'proposal' ]+ '}'
+ * @endcode
+ *
+ * Some parameters are just plain keyword, some have additional numeric
+ * or string arguments. The parameter keywords can be in any order, but
+ * each keyword can only appear once. At least one 'ah' or 'esp' must be
+ * present.
+ *
+ * @param aSpec The specificantion to fill.
+ */
+ {
+ static const TKeyword list[] =
+ {
+ KEYWORD("ah"),
+ KEYWORD("esp"),
+ KEYWORD("encrypt_alg"),
+ KEYWORD("auth_alg"),
+ KEYWORD("identity"),
+ KEYWORD("identity_remote"),
+ KEYWORD("identity_local"),
+ KEYWORD("pfs"),
+ KEYWORD("protocol_specific"),
+ KEYWORD("local_port_specific"),
+ KEYWORD("remote_port_specific"),
+ KEYWORD("proxy_specific"), // -- kept for backward compatibility
+ KEYWORD("local_specific"),
+ KEYWORD("remote_specific"),
+ KEYWORD("src_specific"),
+ KEYWORD("replay_win_len"),
+ KEYWORD("min_auth_bits"),
+ KEYWORD("max_auth_bits"),
+ KEYWORD("min_encrypt_bits"),
+ KEYWORD("max_encrypt_bits"),
+ KEYWORD("hard_lifetime_allocations"),
+ KEYWORD("hard_lifetime_bytes"),
+ KEYWORD("hard_lifetime_addtime"),
+ KEYWORD("hard_lifetime_usetime"),
+ KEYWORD("soft_lifetime_allocations"),
+ KEYWORD("soft_lifetime_bytes"),
+ KEYWORD("soft_lifetime_addtime"),
+ KEYWORD("soft_lifetime_usetime")
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ ,KEYWORD("proposal")
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ };
+ enum // Order must be exactly the same as above
+ {
+ KEYENUM(ah),
+ KEYENUM(esp),
+ KEYENUM(encrypt_alg),
+ KEYENUM(auth_alg),
+ KEYENUM(identity),
+ KEYENUM(identity_remote),
+ KEYENUM(identity_local),
+ KEYENUM(pfs),
+ KEYENUM(protocol_specific),
+ KEYENUM(local_port_specific),
+ KEYENUM(remote_port_specific),
+ KEYENUM(proxy_specific),
+ KEYENUM(local_specific),
+ KEYENUM(remote_specific),
+ KEYENUM(src_specific),
+ KEYENUM(replay_win_len),
+ KEYENUM(min_auth_bits),
+ KEYENUM(max_auth_bits),
+ KEYENUM(min_encrypt_bits),
+ KEYENUM(max_encrypt_bits),
+ KEYENUM(hard_lifetime_allocations),
+ KEYENUM(hard_lifetime_bytes),
+ KEYENUM(hard_lifetime_addtime),
+ KEYENUM(hard_lifetime_usetime),
+ KEYENUM(soft_lifetime_allocations),
+ KEYENUM(soft_lifetime_bytes),
+ KEYENUM(soft_lifetime_addtime),
+ KEYENUM(soft_lifetime_usetime),
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ KEYENUM(proposal),
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ KEYENUM(max_parameters)
+ };
+
+ TInt sa_type_defined = 0;
+ TInt error = KErrNone;
+ token_type val;
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ val = NextToken();
+ TInt propasalsDefined=0;
+ CSecurityProposalSpec* prop = NULL;
+ while (val == token_string)
+#else
+ while ((val = NextToken()) == token_string)
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ {
+ switch (Lookup(list, E_max_parameters, iToken))
+ {
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ case E_proposal:
+ propasalsDefined++;
+ prop = CreateProposalL (*aPolicySpec->iPropList);
+ if ((val=NextToken()) != token_brace_left)
+ {
+ User::Leave(EIpsec_PolicySyntaxError);
+ }
+ break;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ case E_ah:
+ sa_type_defined++;
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iType = SADB_SATYPE_AH;
+ if (prop) prop->iType = SADB_SATYPE_AH;
+#else
+ aSpec.iType = SADB_SATYPE_AH;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_esp:
+ sa_type_defined++;
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iType = SADB_SATYPE_ESP;
+ if (prop) prop->iType = SADB_SATYPE_ESP;
+#else
+ aSpec.iType = SADB_SATYPE_ESP;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_encrypt_alg:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop && (error = Val(prop->iEalg, EDecimal)) == KErrNone &&
+ iSp->FindAlg(EAlgorithmClass_Cipher, prop->iEalg) == NULL)
+ User::Leave(EIpsec_PolicyUnknownEncrypt);
+ if(prop)
+ aPolicySpec->iSpec.iEalg = prop->iEalg;
+#else
+ if ((error = Val(aSpec.iEalg, EDecimal)) == KErrNone &&
+ iSp->FindAlg(EAlgorithmClass_Cipher, aSpec.iEalg) == NULL)
+ User::Leave(EIpsec_PolicyUnknownEncrypt);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_auth_alg:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop && (error = Val(prop->iAalg, EDecimal)) == KErrNone &&
+ (iSp->FindAlg(EAlgorithmClass_Digest, prop->iAalg) == NULL)
+ && (iSp->FindAlg(EAlgorithmClass_Mac, prop->iAalg) == NULL) )
+ User::Leave(EIpsec_PolicyUnknownAuth);
+ if(prop)
+ aPolicySpec->iSpec.iAalg = prop->iAalg ;
+#else
+ if ((error = Val(aSpec.iAalg, EDecimal)) == KErrNone &&
+ iSp->FindAlg(EAlgorithmClass_Digest, aSpec.iAalg) == NULL)
+ User::Leave(EIpsec_PolicyUnknownAuth);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_identity: // temp. backwards compatibility
+ case E_identity_remote:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (aPolicySpec->iSpec.iIdentityRemote)
+ User::Leave(EIpsec_PolicyIdentityDefined);
+ (void)NextToken(); // Advance iToken to the identity value
+ aPolicySpec->iSpec.iIdentityRemote = CIdentity::NewL(iToken);
+#else
+ if (aSpec.iIdentityRemote)
+ User::Leave(EIpsec_PolicyIdentityDefined);
+ (void)NextToken(); // Advance iToken to the identity value
+ aSpec.iIdentityRemote = CIdentity::NewL(iToken);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_identity_local:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (aPolicySpec->iSpec.iIdentityLocal)
+ User::Leave(EIpsec_PolicyIdentityDefined);
+ (void)NextToken(); // Advance iToken to the identity value
+ aPolicySpec->iSpec.iIdentityLocal = CIdentity::NewL(iToken);
+#else
+ if (aSpec.iIdentityLocal)
+ User::Leave(EIpsec_PolicyIdentityDefined);
+ (void)NextToken(); // Advance iToken to the identity value
+ aSpec.iIdentityLocal = CIdentity::NewL(iToken);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_pfs:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iPfs = 1;
+#else
+ aSpec.iPfs = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_protocol_specific:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iMatchProtocol = 1;
+#else
+ aSpec.iMatchProtocol = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_local_port_specific:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iMatchLocalPort = 1;
+#else
+ aSpec.iMatchLocalPort = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_remote_port_specific:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iMatchRemotePort = 1;
+#else
+ aSpec.iMatchRemotePort = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_proxy_specific:
+ // ** should be deprecated -- msa
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iMatchProxy = 1;
+#else
+ aSpec.iMatchProxy = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_local_specific:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iMatchLocal = 1;
+#else
+ aSpec.iMatchLocal = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_remote_specific:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iMatchRemote = 1;
+#else
+ aSpec.iMatchRemote = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_src_specific:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ aPolicySpec->iSpec.iMatchSrc = 1;
+#else
+ aSpec.iMatchSrc = 1;
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_replay_win_len:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ error = Val(aPolicySpec->iSpec.iReplayWindowLength, EDecimal);
+#else
+ error = Val(aSpec.iReplayWindowLength, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_min_auth_bits:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ error = Val(aPolicySpec->iSpec.iMinAuthBits, EDecimal);
+#else
+ error = Val(aSpec.iMinAuthBits, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_max_auth_bits:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iMaxAuthBits, EDecimal);
+ }
+#else
+ error = Val(aSpec.iMaxAuthBits, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_min_encrypt_bits:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iMinEncryptBits, EDecimal);
+ }
+#else
+ error = Val(aSpec.iMinEncryptBits, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_max_encrypt_bits:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iMaxEncryptBits, EDecimal);
+ }
+#else
+ error = Val(aSpec.iMaxEncryptBits, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_hard_lifetime_allocations:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iHard.sadb_lifetime_allocations , EDecimal);
+ }
+#else
+ error = Val(aSpec.iHard.sadb_lifetime_allocations, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_hard_lifetime_bytes:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iHard.sadb_lifetime_bytes , EDecimal);
+ }
+#else
+ error = Val(aSpec.iHard.sadb_lifetime_bytes, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_hard_lifetime_addtime:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iHard.sadb_lifetime_addtime , EDecimal);
+ }
+#else
+ error = Val(aSpec.iHard.sadb_lifetime_addtime, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_hard_lifetime_usetime:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iHard.sadb_lifetime_usetime , EDecimal);
+ }
+#else
+ error = Val(aSpec.iHard.sadb_lifetime_usetime, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_soft_lifetime_allocations:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iSoft.sadb_lifetime_allocations , EDecimal);
+ }
+#else
+ error = Val(aSpec.iSoft.sadb_lifetime_allocations, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_soft_lifetime_bytes:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iSoft.sadb_lifetime_bytes , EDecimal);
+ }
+#else
+ error = Val(aSpec.iSoft.sadb_lifetime_bytes, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_soft_lifetime_addtime:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iSoft.sadb_lifetime_addtime , EDecimal);
+ }
+#else
+ error = Val(aSpec.iSoft.sadb_lifetime_addtime, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+ case E_soft_lifetime_usetime:
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (prop)
+ {
+ error = Val(prop->iSoft.sadb_lifetime_usetime , EDecimal);
+ }
+#else
+ error = Val(aSpec.iSoft.sadb_lifetime_usetime, EDecimal);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ break;
+
+ default:
+ User::Leave(EIpsec_PolicyUnknownSpec);
+ }
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ val = CheckProposalCloseAndMoreProposals(propasalsDefined);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (error != KErrNone)
+ User::Leave(EIpsec_PolicyNumberExpected);
+ }
+ if (val != token_brace_right)
+ User::Leave(EIpsec_PolicyCloseBraceExpected);
+ else if (sa_type_defined < 1)
+ User::Leave(EIpsec_PolicyNoType);
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ else if ((aPolicySpec->iSpec.iType == SADB_SATYPE_AH) && !aPolicySpec->iSpec.iAalg)
+ User::Leave(EIpsec_PolicyNoAuthAlgorithm);
+ else if ((aPolicySpec->iSpec.iType == SADB_SATYPE_ESP) && !aPolicySpec->iSpec.iEalg)
+ User::Leave(EIpsec_PolicyNoEncryptAlgorithm);
+#else
+ else if (sa_type_defined > 1)
+ User::Leave(EIpsec_PolicyTooManyTypes);
+ else if ((aSpec.iType == SADB_SATYPE_AH) && !aSpec.iAalg)
+ User::Leave(EIpsec_PolicyNoAuthAlgorithm);
+ else if ((aSpec.iType == SADB_SATYPE_ESP) && !aSpec.iEalg)
+ User::Leave(EIpsec_PolicyNoEncryptAlgorithm);
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ }
+
+
+void TParser::ParseAssociationL()
+ /**
+ * Parse security association
+ * @code name '=' '{' ParseAssociationParametersL
+ * @endcode
+ */
+ {
+ if (NextToken() != token_string)
+ User::Leave(EIpsec_PolicySpecName);
+ // Allocate a slot for the new association specification
+ CPolicySpec *const ps = new (ELeave) CPolicySpec();
+ if (iSp->iSpecs.Append(ps) != KErrNone)
+ {
+ ps->Close();
+ User::Leave(KErrNoMemory);
+ }
+ ps->iName = HBufC::NewMaxL(iToken.Length());
+ *ps->iName = iToken;
+
+ if (NextToken() != token_equal ||
+ NextToken() != token_brace_left)
+ User::Leave(EIpsec_PolicySyntaxError);
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ ParseAssociationParametersL(ps);
+#else
+ ParseAssociationParametersL(ps->iSpec);
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ }
+
+void TParser::ParseSecurityBundleL(RPolicyActions &aActions, CTransportSelector *aTS)
+ /**
+ * Parse security actions
+ * @code [ sa-name '(' [ address ] ')' ]* '}'
+ * @endcode
+ *
+ * Parse a (possibly empty) list of references to security specifications. This will
+ * be the bundle of security actions for a selector.
+ *
+ * @retval aActions The colleted actions
+ * @param aTS The traffic selector.
+ */
+ {
+ _LIT(K_tunnel, "tunnel");
+
+ token_type val;
+
+ TUint opt = 0;
+
+ for (;;)
+ {
+ val = NextToken();
+ //
+ // Experimental addition, allow optional bundle items
+ // by prefixing them with '?'...
+ //
+ if (opt == 0 && val == token_question)
+ {
+ opt = 1;
+ continue;
+ }
+ else if (val != token_string)
+ break;
+ // A temporary(?) special kluge: if the keyword is 'tunnel'
+ // assume this is a plain tunnel specification, without any
+ // relation to the IPSEC. if nobody defined a "tunnel" sa
+ // specification. (should probably disallow 'tunnel' as SA
+ // spec name, to avoid confusion.. )
+ //
+ CPolicySpec *spec = iSp->FindSpec(iToken);
+ if (spec == NULL && iToken.Compare(K_tunnel) != 0)
+ User::Leave(EIpsec_PolicySpecNotFound);
+
+ if (NextToken() != token_par_left)
+ User::Leave(EIpsec_PolicyLeftParen);
+
+ CPolicyAction *action = new (ELeave) CPolicyAction;
+ if (aActions.Append(action) != KErrNone)
+ {
+ action->Close();
+ User::Leave(KErrNoMemory);
+ }
+ if ((action->iSpec = spec) != NULL)
+ spec->Open();
+ // Record the current selector into each action (this is to make it
+ // easier to generate the TS list into Acquire message).
+ if ((action->iTS = aTS) != NULL)
+ aTS->Open();
+ action->iOptional = opt;
+
+ if ((val = NextToken()) == token_string)
+ {
+ SetAddressOrEndPointL(action->iTunnel, 0, EIpsec_PolicyInvalidIpAddress);
+ action->iIsTunnel = 1; // Flag a tunnel.
+ val = NextToken();
+ }
+ if (val != token_par_right)
+ User::Leave(EIpsec_PolicyRightParen);
+ opt = 0; // Optional only affects single item at time.
+ }
+ if (val != token_brace_right)
+ User::Leave(EIpsec_PolicyCloseBraceExpected);
+ }
+
+
+void TParser::SetAddressOrEndPointL(RIpAddress &aAddr, TInt aMask, TInt aError)
+ /**
+ * Initiliaze address from current token.
+ *
+ * The token can contain direct address literal or a name of an end point.
+ * If a name is used, it must exist.
+ *
+ * @retval aAddr The address to initialize.
+ * @param aMask Non-zero, if address is used as mask.
+ * @param aError The error to use if end point does not exist (leave)
+ */
+ {
+ TIpAddress addr;
+ if (addr.SetAddress(iToken, aMask) == KErrNone)
+ {
+ // plain address
+ User::LeaveIfError(aAddr.Open(iEp, addr));
+ }
+ else if (aAddr.Open(iEp, iToken) != KErrNone)
+ {
+ // Named endpoint not found
+ User::Leave(aError);
+ }
+ }
+
+void TParser::ParseAddressL(RIpAddress &aAddr, TInt aMask, TInt aError)
+ /**
+ * Parse next token as address.
+ * @code address
+ * @endcode
+ *
+ * @retval aAddr The address to initialize
+ * @param aMask Non-zero, if address is used as mask.
+ * @param aError The error to use, if error
+ */
+ {
+ if (NextToken() != token_string)
+ {
+ User::Leave(aError);
+ }
+ else
+ {
+ SetAddressOrEndPointL(aAddr, aMask, aError);
+ }
+ }
+
+
+void TParser::ParseAddressAndMaskL(RIpAddress &aAddr, RIpAddress& aMask)
+ /**
+ * Parse two tokens as addres and address mask
+ * @code ParseAddressL ParseAddressL
+ * @endcode
+ *
+ * @param aAddr The address to initialize
+ * @param aMask The mask to initialize
+ */
+ {
+ ParseAddressL(aAddr, 0, EIpsec_PolicyIpAddressExpected);
+ ParseAddressL(aMask, 1, EIpsec_PolicyIpMaskExpected);
+ }
+
+token_type TParser::TransportSelectorL(CTransportSelector *&aTs)
+ /**
+ * Parse one transport selector.
+ * @code [
+ * 'remote' ParseAddressAndMaskL | 'local' ParseAddressAndMaskL |
+ * 'user_id' | 'protocol' number |
+ * 'local_port' number | 'remote_port' number |
+ * 'icmp_type' number | 'type' number | 'icmp_code' number ]*
+ * @endcode
+ */
+ {
+ static const TKeyword list[] =
+ {
+ KEYWORD("remote"),
+ KEYWORD("local"),
+ KEYWORD("user_id"),
+ KEYWORD("protocol"),
+ KEYWORD("local_port"),
+ KEYWORD("remote_port"),
+ KEYWORD("icmp_type"),
+ KEYWORD("icmp_code"),
+ KEYWORD("type"),
+ };
+
+ enum // Order must be exactly the same as above
+ {
+ KEYENUM(remote),
+ KEYENUM(local),
+ KEYENUM(user_id),
+ KEYENUM(protocol),
+ KEYENUM(local_port),
+ KEYENUM(remote_port),
+ KEYENUM(icmp_type),
+ KEYENUM(icmp_code),
+ KEYENUM(type), // synonym for "icmp_type" (use for MH and similar)
+
+ KEYENUM(max_parameters)
+ };
+
+ token_type val;
+ //
+ // By default, a new selector will match everything (mask is all zero)
+ //
+ RPolicySelectorInfo data;
+ RPolicySelectorInfo mask;
+ data.FillZ();
+ mask.FillZ();
+
+#if OLD_SELECTOR_ORDERING
+ // If selector already exists, continue filling it.
+ if (aTs != NULL)
+ {
+ data = aTs->iData;
+ mask = aTs->iMask;
+ aTs->Close();
+ aTs = NULL;
+ }
+#endif
+
+ do
+ {
+ TUint8 tmp8;
+
+ switch (Lookup(list, E_max_parameters, iToken))
+ {
+ case E_remote:
+ ParseAddressAndMaskL(data.iRemote, mask.iRemote);
+ break;
+ case E_local:
+ ParseAddressAndMaskL(data.iLocal, mask.iLocal);
+ break;
+ case E_user_id:
+ break; // Needs to be examined, TIdentity? -- msa
+ case E_protocol:
+ mask.iProtocol = 0xFF;
+ User::LeaveIfError(Val(data.iProtocol, EDecimal));
+ break;
+ case E_local_port:
+ if (mask.iPortLocal)
+ User::Leave(EIpsec_PolicySyntaxError); // Already defined (or type/code)
+ mask.iPortLocal = 0xFFFF;
+ User::LeaveIfError(Val(data.iPortLocal, EDecimal));
+ mask.iFlags |= KTransportSelector_PORTS;
+ data.iFlags |= KTransportSelector_PORTS;
+ break;
+ case E_remote_port:
+ if (mask.iPortRemote)
+ User::Leave(EIpsec_PolicySyntaxError); // Already defined
+ mask.iPortRemote = ~0;
+ User::LeaveIfError(Val(data.iPortRemote, EDecimal));
+ mask.iFlags |= KTransportSelector_PORTS;
+ data.iFlags |= KTransportSelector_PORTS;
+ break;
+ case E_icmp_type:
+ case E_type:
+ if ((mask.iPortLocal | mask.iPortRemote) & 0xFF00)
+ User::Leave(EIpsec_PolicySyntaxError); // Already defined (or port used)
+ mask.iPortLocal |= 0xFF00;
+ User::LeaveIfError(Val(tmp8, EDecimal));
+ data.iPortLocal |= tmp8 << 8;
+ // For Type/Code remote port selector is always same as local port value
+ mask.iPortRemote = mask.iPortLocal;
+ data.iPortRemote = data.iPortLocal;
+ mask.iFlags |= KTransportSelector_PORTS;
+ data.iFlags &= ~KTransportSelector_PORTS;
+ break;
+ case E_icmp_code:
+ if ((mask.iPortLocal | mask.iPortRemote) & 0x00FF)
+ User::Leave(EIpsec_PolicySyntaxError); // Already defined (or port used)
+ mask.iPortLocal |= 0x00FF;
+ User::LeaveIfError(Val(tmp8, EDecimal));
+ data.iPortLocal |= tmp8;
+ // For Type/Code remote port selector is always same as local port value
+ mask.iPortRemote = mask.iPortLocal;
+ data.iPortRemote = data.iPortLocal;
+ mask.iFlags |= KTransportSelector_PORTS;
+ data.iFlags &= ~KTransportSelector_PORTS;
+ break;
+ default:
+#if OLD_SELECTOR_ORDERING
+ val = token_string;
+ goto wrapup;
+#else
+ User::Leave(EIpsec_PolicyUnknownSelector);
+#endif
+ }
+ }
+ while
+ ((val = NextToken()) == token_string);
+#if OLD_SELECTOR_ORDERING
+wrapup:
+#endif
+ aTs = new (ELeave) CTransportSelector(data, mask, NULL);
+ return val;
+ }
+
+void TParser::ParseSelectorL(CPolicySelector *&aPs)
+ /**
+ * Parse a policy selector
+ * @code [ 'final' | 'merge' | 'outbound' | 'inbound' | 'if' interface ]*
+ * TransportSelectorL '=' ( '{' ParseSecurityBundleL | 'drop' )
+ * @endcode
+ */
+ {
+ static const TKeyword list[] =
+ {
+ KEYWORD("final"),
+ KEYWORD("merge"),
+ KEYWORD("outbound"),
+ KEYWORD("inbound"),
+ KEYWORD("if"),
+ };
+
+ enum // Order must be exactly the same as above
+ {
+ KEYENUM(final),
+ KEYENUM(merge),
+ KEYENUM(outbound),
+ KEYENUM(inbound),
+ KEYENUM(if),
+
+ KEYENUM(max_parameters)
+ };
+
+ _LIT(K_drop, "drop");
+
+ token_type val;
+ //
+ aPs = new (ELeave) CPolicySelector();
+
+ //
+ // ...by default the "merge" must be off to match.
+ //
+ aPs->iFilterMask = KPolicyFilter_MERGE;
+
+ do
+ {
+#if OLD_SELECTOR_ORDERING
+ check_again:
+#endif
+ switch (Lookup(list, E_max_parameters, iToken))
+ {
+ case E_final:
+ if (aPs->iFilterData & KPolicyFilter_FINAL)
+ User::Leave(EIpsec_PolicySyntaxError); // Duplicate "final" keyword.
+ // No need to set "mask", this is a flag only.
+ aPs->iFilterData |= KPolicyFilter_FINAL;
+ break;
+ case E_merge:
+ if ((aPs->iFilterMask & KPolicyFilter_MERGE) == 0)
+ User::Leave(EIpsec_PolicySyntaxError); // Duplicate "merge" keyword.
+ aPs->iFilterMask &= ~KPolicyFilter_MERGE; // allow this selector to be merged.
+ break;
+ case E_outbound:
+ if (aPs->iFilterData & KPolicyFilter_SYMMETRIC)
+ User::Leave(EIpsec_PolicyInboundOutbound);
+ aPs->iFilterData |= KPolicyFilter_OUTBOUND;
+ aPs->iFilterMask |= KPolicyFilter_OUTBOUND;
+ break;
+ case E_inbound:
+ if (aPs->iFilterData & KPolicyFilter_SYMMETRIC)
+ User::Leave(EIpsec_PolicyInboundOutbound);
+ aPs->iFilterData |= KPolicyFilter_INBOUND;
+ aPs->iFilterMask |= KPolicyFilter_INBOUND;
+ break;
+ case E_if:
+ if (aPs->iInterface || NextToken() != token_string)
+ User::Leave(EIpsec_PolicySyntaxError); // <-- need own error code?
+ aPs->iInterface = iSp->LookupInterfaceL(iToken);
+ break;
+ default:
+ val = TransportSelectorL(aPs->iTS);
+#if OLD_SELECTOR_ORDERING
+ if (Lookup(list, E_max_parameters, iToken) < E_max_parameters)
+ goto check_again;
+#endif
+ goto wrapup;
+ }
+ }
+ while
+ ((val = NextToken()) == token_string);
+wrapup:
+
+ if (val != token_equal)
+ User::Leave(EIpsec_PolicySyntaxError);
+ if (NextToken() == token_brace_left)
+ ParseSecurityBundleL(aPs->iActions, aPs->iTS);
+ else if (iToken.Compare(K_drop) == 0)
+ aPs->iFilterData |= KPolicyFilter_DROP;
+ else
+ User::Leave(EIpsec_PolicySyntaxError);
+ }
+
+#ifdef __VC32__
+#pragma warning(disable : 4097) // typedef-name used as synonym for class-name
+#endif
+
+TParser::TParser(CSecurityPolicy *aSp, const TDesC &aPolicy, REndPoints &aEp) :
+ TLex(aPolicy), iSp(aSp), iEp(aEp)
+ {
+ }
+
+void TParser::ParseL(TUint aStartOffset)
+ /**
+ * Parse complete security policy
+ * @code (
+ * 'sa' ParseAssociationL |
+ * 'encrypt' ParseAlgorithmMappingL |
+ * 'auth' ParseAlgorithmMappingL |
+ * 'ep' ParseEndPointL )*
+ * @endcode
+ *
+ * @param aStartOffset Starting offset of the actual policy
+ * @leave error on syntax or other error.
+ */
+ {
+ static const TKeyword list[] =
+ {
+ KEYWORD("sa"),
+ KEYWORD("encrypt"),
+ KEYWORD("auth"),
+ KEYWORD("ep"),
+ };
+ enum
+ {
+ KEYENUM(sa),
+ KEYENUM(encrypt),
+ KEYENUM(auth),
+ KEYENUM(ep),
+
+ KEYENUM(max_list)
+ };
+
+ CPolicySelector **last = &iSp->iSelectors;
+
+ Inc(aStartOffset);
+ while (NextToken() == token_string)
+ {
+ switch (Lookup(list, E_max_list, iToken))
+ {
+ case E_sa:
+ ParseAssociationL();
+ break;
+ case E_encrypt:
+ ParseAlgorithmMappingL(EAlgorithmClass_Cipher);
+ break;
+ case E_auth:
+ ParseAlgorithmMappingL(EAlgorithmClass_Digest);
+ break;
+ case E_ep:
+ ParseEndPointL();
+ break;
+ default:
+ ParseSelectorL(*last);
+ if (*last)
+ last = &(*last)->iNext;
+ break;
+ }
+ }
+ if (!Eos())
+ // Parsing didn't detect error, but not all parsed!
+ User::Leave(EIpsec_PolicySyntaxError);
+ }
+
+
+CSecurityPolicy::CSecurityPolicy()
+ /**
+ * Constructor.
+ */
+ {
+ IPSEC_OBJECT_INC;
+ }
+
+
+TInt CSecurityPolicy::SetPolicy(CSecurityPolicy * &aPolicy, const TDesC &aNewPolicy, TUint &aOffset, REndPoints &aEp)
+ /**
+ * Construct a new binary policy and replace a the current with it.
+ *
+ * @retval aPolicy Holder of the current binary policy
+ * @param aNewPolicy The new policy definition (text string)
+ * @retval aOffset The initial start, and final point in parsing
+ * @param aEp The End point collection to store the named endpoints
+ *
+ * @return KErrNone on success, and some < 0 error code otherwise.
+ */
+ {
+ delete aPolicy;
+ aPolicy = new CSecurityPolicy();
+ if (aPolicy == NULL)
+ return KErrNoMemory;
+
+ TParser parser(aPolicy, aNewPolicy, aEp);
+ aPolicy->iAlgorithms = new CAlgorithmList;
+ if (aPolicy->iAlgorithms == NULL)
+ return KErrNoMemory;
+ TRAPD(result, parser.ParseL(aOffset); );
+ aOffset = parser.MarkedOffset();
+ return result;
+ }
+
+CSecurityPolicy::~CSecurityPolicy()
+ /**
+ * Descructor.
+ */
+ {
+ // release association descriptions/templates
+ for (TInt i = iSpecs.Count(); --i >= 0; )
+ {
+ CPolicySpec *const s = iSpecs[i];
+ if (s)
+ s->Close();
+ }
+ iSpecs.Close();
+
+ // release End Points assocated with this policy
+ for (TInt j = iEndPoints.Count(); --j >= 0; )
+ {
+ iEndPoints[j].Close();
+ }
+ iEndPoints.Close();
+
+ // release the policy selectors
+ CPolicySelector *ps;
+ while ((ps = iSelectors) != NULL)
+ {
+ iSelectors = ps->iNext;
+ delete ps;
+ }
+
+ // release the named interface entries
+ while (iInterfaces)
+ {
+ CSelectorInterface *tmp = iInterfaces;
+ iInterfaces = tmp->iNext;
+ delete tmp;
+ }
+
+ // ..and algorithms table
+ delete iAlgorithms;
+ IPSEC_OBJECT_DEC;
+ }
+
+CPolicySelector::CPolicySelector()
+ /**
+ * Constructor
+ */
+ {
+ IPSEC_OBJECT_INC;
+ }
+
+CPolicySelector::~CPolicySelector()
+ /**
+ * Descructor.
+ */
+ {
+
+ // Release policy actions
+ for (TInt i = iActions.Count(); --i >= 0; )
+ {
+ CPolicyAction *const action = iActions[i];
+ if (action)
+ action->Close();
+ }
+ iActions.Close();
+
+ // Release transport selector(s)
+ if (iTS)
+ iTS->Close();
+
+ IPSEC_OBJECT_DEC;
+ }
+
+//
+CSelectorInterface::CSelectorInterface()
+ /**
+ * Constructor
+ */
+ {
+ IPSEC_OBJECT_INC;
+ }
+
+CSelectorInterface::~CSelectorInterface()
+ /**
+ * Descructor.
+ */
+ {
+ delete iName;
+ IPSEC_OBJECT_DEC;
+ }
+
+const CSelectorInterface *CSecurityPolicy::LookupInterfaceL(const TDesC &aName)
+ /**
+ * Locate interface by name from policy.
+ *
+ * Return an existing interface object, if found and otherwise,
+ * create and initialize new object.
+ *
+ * @param aName The interface name
+ * @return The interface
+ * @leave KErrNoMemory, if allocation fails.
+ */
+ {
+ CSelectorInterface *si;
+ //
+ // See if interface already exists
+ //
+ for (si = iInterfaces; si != NULL; si = si->iNext)
+ if (aName.Compare(*si->iName) == 0)
+ return si; // Already exists, reuse
+ //
+ // First time occurrence of this interface name, create a new entry
+ //
+ si = new (ELeave) CSelectorInterface();
+ si->iNext = iInterfaces;
+ iInterfaces = si;
+ si->iName = HBufC::NewMaxL(aName.Length());
+ *si->iName = aName;
+ return si;
+ }
+
+CPolicySpec *CSecurityPolicy::FindSpec(const TDesC &aName) const
+ /**
+ * Locate security association specification by name.
+ *
+ * @param aName
+ * @return The specification or NULL, if not found
+ *
+ */
+ {
+ for (TInt i = iSpecs.Count(); i > 0; )
+ {
+ CPolicySpec *const s = iSpecs[--i];
+ if (aName.Compare(*s->iName) == 0)
+ return s;
+ }
+ return NULL;
+ }
+
+//
+
+CPolicyAction::~CPolicyAction()
+ /**
+ * Desctructor.
+ */
+ {
+ if (iSpec)
+ iSpec->Close();
+ if (iTS)
+ iTS->Close();
+ }
+
+//
+
+CPolicySpec::CPolicySpec()
+ {
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ iPropList = CPropList::NewL(1);
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ }
+
+
+CPolicySpec::~CPolicySpec()
+ /**
+ * Destructor.
+ */
+ {
+ delete iName;
+ //
+ // Identity blocks are reference counted, there
+ // may still be SA's referring to them
+ //
+ if (iSpec.iIdentityLocal)
+ iSpec.iIdentityLocal->Close();
+ if (iSpec.iIdentityRemote)
+ iSpec.iIdentityRemote->Close();
+ }