--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linklayerprotocols/pppnif/SPPP/PPPCHAP.CPP Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,472 @@
+// Copyright (c) 1997-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:
+// Authentication Protocol (CHAP) - RFC 1994, containing source code
+// common to all PPP authentication protocols derived from CHAP.
+//
+//
+
+/**
+ @file
+ @brief Source file for the implementation of PPP Challenge Handshake
+ @internalComponent
+*/
+
+#include "PPPCHAP.H"
+
+CPppChap::~CPppChap()
+/**
+ Destructor.
+ @internalComponent
+*/
+ {
+ if (iPppLcp != 0)
+ {
+ iChallengePacket.Free();
+ TimerDelete();
+ }
+ }
+
+void CPppChap::InitL(CPppLcp* aLcp)
+/**
+ @copydoc CPppAuthentication::InitL(CPppLcp*)
+ @see CPppAuthentication::InitL(CPppLcp*)
+ @internalComponent
+*/
+ {
+ CPppAuthentication::InitL(aLcp);
+ TimerConstructL(KPppFsmTimerPriority);
+ Register();
+ }
+
+void CPppChap::LowerLayerUp()
+/**
+ @copydoc MPppRecvr::LowerLayerUp()
+ @see MPppRecvr::LowerLayerUp()
+ @internalComponent
+*/
+ {
+ ASSERT(iPppLcp != 0);
+ AuthenticateRequest();
+ }
+
+
+void CPppChap::LowerLayerDown(TInt /*aStatus*/)
+/**
+ @copydoc MPppRecvr::LowerLayerDown(TInt)
+ @see MPppRecvr::LowerLayerDown(TInt)
+ @internalComponent
+*/
+ {
+ ASSERT(iPppLcp != 0);
+ TimerCancel();
+ }
+
+
+void CPppChap::AuthenticateComplete(TInt aStatus)
+/**
+ @copydoc CPppAuthentication::AuthenticateComplete(TInt)
+ @see CPppAuthentication::AuthenticateComplete(TInt)
+ @internalComponent
+*/
+ {
+ ASSERT(iPppLcp != 0);
+ if (aStatus==KErrNone)
+ {
+ if (!iChallengePacket.IsEmpty())
+ {
+ iResponseRetryCount = 0;
+ //ignore Error, if fails it will time out
+ //and try again anyway.
+ TRAP_IGNORE(RespondL());
+ }
+ }
+ else
+ DoFail(aStatus);
+ }
+
+
+TBool CPppChap::RecvFrame(RMBufChain& aPacket)
+/**
+ @copydoc MPppRecvr::RecvFrame(RMBufChain&)
+ @see MPppRecvr::RecvFrame(RMBufChain&)
+ @internalComponent
+*/
+ {
+ ASSERT(iPppLcp != 0);
+
+ RMBufPacket pkt;
+ pkt.Assign(aPacket);
+ pkt.Unpack();
+ RMBufPktInfo* info = pkt.Info();
+
+ if (IsInactive())
+ {
+ pkt.Free();
+ return EFalse;
+ }
+
+
+// Extract and drop LCP header
+ pkt.Align(4);
+
+ if (info->iLength < KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize)
+ {
+// Too short!
+ pkt.Free();
+ return EFalse;
+ }
+
+
+// check that the length of the packet is OK
+ TUint16 length = BigEndian::Get16(pkt.First()->Ptr() +
+ KPppChapCodeFieldSize +
+ KPppChapIdFieldSize);
+
+ if (info->iLength < length)
+ {
+// Too short!
+ pkt.Free();
+ return EFalse;
+ }
+ else if (info->iLength > length)
+ pkt.TrimEnd(length);
+
+ ASSERT(pkt.Length()==length);
+
+ TUint8 code = *(pkt.First()->Ptr());
+
+ TInt ret;
+ switch (code)
+ {
+ case KPppChapChallengeCode:
+ {
+ TRAP(ret, ChallengeL(pkt));
+ }
+ break;
+
+ case KPppChapResponseCode:
+// {
+// TInt vc = *ptr++;
+// TUint8* vp = ptr;
+// TInt nc = len-(vc+1);
+// TUint8* np = ptr+vc;
+// }
+ break;
+
+ case KPppChapSuccessCode:
+ {
+ TRAP(ret, SuccessL(pkt));
+ }
+ break;
+
+ case KPppChapFailureCode:
+ {
+ TRAP(ret, FailureL(pkt));
+
+ if (ret!=KErrNone)
+ DoFail(KErrIfAuthenticationFailure);
+ }
+ break;
+
+ // default: invalid CHAP packet code
+ // simply ignore the packet
+ }
+
+ pkt.Free();
+ return EFalse;
+ }
+
+// RFC 1994: "The Challenge-Handshake Authentication Protocol (CHAP)
+// is used to periodically verify the identity of the peer using a
+// 3-way handshake. This is done upon initial link establishment, and
+// MAY be repeated anytime after the link has been established."
+
+
+void CPppChap::ChallengeL(RMBufPacket& aPacket)
+/**
+ Processes a CHAP Challenge packet and attempts to respond to the
+ challenge.
+ @param aPacket [in] The CHAP Challenge packet to be processed.
+ @internalComponent
+*/
+ {
+ TimerCancel();
+ ProcessChallengePacketL(aPacket);
+
+ if (IsAuthenticateRequestDone())
+ {
+ iResponseRetryCount = 0;
+ RespondL();
+ }
+ }
+
+
+void CPppChap::CheckChallengePacketL(RMBufPacket& aPacket)
+/**
+ Checks that a CHAP Challenge packet is valid. Leaves if the packet
+ is malformed.
+ @param aPacket [in] The CHAP Challenge packet to be checked.
+ @internalComponent
+*/
+ {
+// In the case of MS-CHAP-V1 and MS-CHAP-V2 the Challenge Name may be
+// empty. RFC 1994: "The Name field is one or more octets [...]".
+// RFC2433, RFC2759: "Microsoft authenticators do not currently
+// provide information in the Name field. This may change in the
+// future."
+ __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize +
+ KPppChapValueSizeFieldSize +
+ KPppChapMinValueSize,
+ User::Leave(KErrUnderflow));
+
+ TUint8 valueSize = *(aPacket.First()->Ptr() +
+ KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize);
+
+ __ASSERT_ALWAYS(valueSize >= KPppChapMinValueSize,
+ User::Leave(KErrUnderflow));
+
+ __ASSERT_ALWAYS(valueSize <= aPacket.Length() -
+ KPppChapCodeFieldSize -
+ KPppChapIdFieldSize -
+ KPppChapLengthFieldSize -
+ KPppChapValueSizeFieldSize,
+ User::Leave(KErrOverflow));
+ }
+
+
+void CPppChap::ProcessChallengePacketL(RMBufPacket& aPacket)
+/**
+ Processes a CHAP Challenge packet.
+ @param aPacket [in] The CHAP Challenge packet to be processed.
+ @internalComponent
+*/
+ {
+ CheckChallengePacketL(aPacket);
+
+ iChallengePacket.Free();
+ iChallengePacket.Assign(aPacket);
+
+// go past the CHAP Code field and
+// read the CHAP Identifier field
+ iCurrentId = *(iChallengePacket.First()->Ptr()
+ + KPppChapCodeFieldSize);
+
+// Go past the CHAP Code field, the CHAP Identifier field and the CHAP
+// Length field and read the CHAP Value-Size field.
+ TUint8 valueSize = *(iChallengePacket.First()->Ptr() +
+ KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize);
+
+// Go past the CHAP Code field, the CHAP Identifier field, the CHAP
+// Length field and the CHAP Value-Size field and read the CHAP Value
+// field
+ iChallengeRef.Set(iChallengePacket.First()->Ptr() +
+ KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize +
+ KPppChapValueSizeFieldSize,
+ valueSize,
+ valueSize);
+ }
+
+
+void CPppChap::RespondL()
+/**
+ Responds to the latest CHAP Challenge received.
+ @internalComponent
+*/
+ {
+ ASSERT(!iChallengePacket.IsEmpty());
+ ASSERT(IsAuthenticateRequestDone());
+
+ MakeResponseL(iCurrentId,
+ iChallengeRef,
+ iResponseValueRef,
+ iResponseNameRef);
+ SendResponseL(iCurrentId, iResponseValueRef, iResponseNameRef);
+
+ if (++iResponseRetryCount < KPppChapMaxResponseRetryCount)
+ TimerAfter(KPppChapResponseRetryTimerPeriod* 1000);
+ }
+
+
+void CPppChap::MakeResponsePacketLC(TUint8 aIdentifier,
+ const TDesC8& aValue,
+ const TDesC8& aName,
+ RMBufPacket& aPacket)
+/**
+ Creates a CHAP response Packet.
+ @param aIdentifier [in] The CHAP Response Identifier.
+ @param aValue [in] The CHAP Response Value.
+ @param aName [in] The CHAP Response Name.
+ @param aPacket [out] The CHAP Response packet.
+ @internalComponent
+*/
+ {
+ ASSERT(aValue.Length() <= KMaxTInt8);
+ ASSERT(aName.Length() <=
+ KMaxTInt16 -
+ KPppChapCodeFieldSize -
+ KPppChapIdFieldSize -
+ KPppChapLengthFieldSize -
+ KPppChapValueSizeFieldSize -
+ aValue.Length());
+
+ TUint16 length = static_cast<TUint16>(KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize +
+ KPppChapValueSizeFieldSize +
+ aValue.Length() +
+ aName.Length());
+
+ aPacket.AllocL(length);
+ CleanupStack::PushL(aPacket);
+ RMBufPktInfo* info = aPacket.NewInfoL();
+
+// Construct packet header
+ TUint8* ptr = aPacket.First()->Ptr();
+
+// write the CHAP Code field
+ *ptr = KPppChapResponseCode;
+ ptr += KPppChapCodeFieldSize;
+
+// write the CHAP Identifier field
+ *ptr = aIdentifier;
+ ptr += KPppChapIdFieldSize;
+
+// write the CHAP Length field
+ BigEndian::Put16(ptr, length);
+ ptr += KPppChapLengthFieldSize;
+
+// write the CHAP Value-Size field
+ *ptr = static_cast<TUint8>(aValue.Length());
+ ptr += KPppChapValueSizeFieldSize;
+
+ Mem::Copy(ptr, aValue.Ptr(), aValue.Length());
+ ptr += aValue.Length();
+
+ Mem::Copy(ptr, aName.Ptr(), aName.Length());
+ ptr += aName.Length();
+
+ info->iLength = length;
+ TPppAddr::Cast((info->iDstAddr)).SetProtocol(KPppIdChap);
+ aPacket.Pack();
+ }
+
+
+void CPppChap::SendResponseL(TUint8 aResponseId,
+ const TDesC8& aResponseValue,
+ const TDesC8& aResponseName)
+/**
+ Generates a CHAP Response packet and sends it to the peer.
+ @param aResponseId [in] The CHAP Response Identifier.
+ @param aResponseValue [in] The CHAP Response Value.
+ @param aResponseName [in] The CHAP Response Name.
+ @internalComponent
+*/
+ {
+ RMBufPacket packet;
+ MakeResponsePacketLC(aResponseId,
+ aResponseValue,
+ aResponseName,
+ packet);
+ SendFrame(packet);
+ CleanupStack::Pop(); // packet
+ }
+
+
+void CPppChap::SuccessL(RMBufPacket& aPacket)
+/**
+ Processes a CHAP Success packet and takes action to complete the
+ authentication.
+ @param aPacket [in] The CHAP Success packet to be processed.
+ @internalComponent
+*/
+ {
+ __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize,
+ User::Leave(KErrUnderflow));
+
+// check the id
+ if (!CheckIdentifier(aPacket))
+ User::Leave(KErrGeneral);
+
+ TimerCancel();
+ DoSucceed();
+ if (iPppLcp->CallbackEnabled() &&
+ iPppLcp->CallbackRequestType() !=
+ ECallbackIETFRequestTypeMSCBCP)
+ {
+ iPppLcp->CallbackGrantedAndAuthenticated();
+ iPppLcp->TerminateLink(MNifIfNotify::ECallBack);
+ }
+ }
+
+
+void CPppChap::FailureL(RMBufPacket& aPacket)
+/**
+ Processes a CHAP Failure packet and takes action to handle the
+ authentication failure.
+ @param aPacket [in] The CHAP Failure packet to be processed.
+ @internalComponent
+*/
+ {
+ __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize,
+ User::Leave(KErrUnderflow));
+
+// check the id
+ if (!CheckIdentifier(aPacket))
+ User::Leave(KErrGeneral);
+
+ TimerCancel();
+ DoFail(KErrIfAuthenticationFailure);
+ }
+
+
+void CPppChap::TimerComplete(TInt /*aStatus*/)
+/**
+ Signals that the response retry timer has expired.
+ @param aStatus [in] A status code.
+ @see MTimer::TimerComplete(TInt)
+ @internalComponent
+*/
+ {
+ ASSERT(iPppLcp != 0);
+ //ignore Error, if fails it will time out
+ //and try again anyway.
+ TRAP_IGNORE(RetryResponseL());
+ }
+
+
+void CPppChap::RetryResponseL()
+/**
+ Resends the latest CHAP Response sent.
+ @internalComponent
+*/
+ {
+ SendResponseL(iCurrentId, iResponseValueRef, iResponseNameRef);
+
+ if (++iResponseRetryCount < KPppChapMaxResponseRetryCount)
+ TimerAfter(KPppChapResponseRetryTimerPeriod* 1000);
+ }