diff -r 000000000000 -r af10295192d8 linklayerprotocols/pppnif/SPPP/PPPCHAP.CPP --- /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(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(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); + }