diff -r 000000000000 -r 72b543305e3a email/pop3andsmtpmtm/popservermtm/src/cpopsaslauthhelper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/pop3andsmtpmtm/popservermtm/src/cpopsaslauthhelper.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,418 @@ +// Copyright (c) 2008-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: +// + +#include "cpopsaslauthhelper.h" +#include +#include "POPS.PAN" // pop's panic codes + +//string constants containing POP3 AUTH command +_LIT8(KPop3AuthCommand, "AUTH "); +_LIT8(KCramMD5Mechanism, "CRAM-MD5"); +_LIT8(KPlainMechanism, "PLAIN "); +_LIT8(KPop3AuthLoginCommand, "AUTH LOGIN\r\n"); +_LIT8(KPop3CrLf,"\r\n"); + +_LIT8(KPop3AuthBase64StringUsername,"username*"); // To match a folded 'username:' or 'username' +_LIT8(KPop3AuthBase64StringPassword,"password*"); // To match a folded 'password:' or 'password' + +const TInt KMaxLengthOfPlainMessageComponent = 255; +const TInt KMd5BlockLength = 64; + +#define BASE64LEN(x) ((x*4)/3) // Every 3 bytes will be turned into 4 bytes + +const TInt KPreambleLength = 18; //"AUTH LOGIN\r\nPLAIN " +const TInt KMaxLengthOfPlainMessage= KPreambleLength + 1/*NUL*/ + KMaxLengthOfPlainMessageComponent/*Username*/ + 1/*NUL*/ + KMaxLengthOfPlainMessageComponent/*Password*/ + 2/* /r/n */; +const TInt KMaxLengthOfPlainMessageBase64= BASE64LEN(KMaxLengthOfPlainMessage); + + +/** +Constructor for CPopAuthMechanismHelper +*/ +CPopAuthMechanismHelper::CPopAuthMechanismHelper(const CImPop3Settings& aSettings) : iSettings(aSettings) + { + } + +/** +Allocates and constructs a CPopAuthCramMd5MechanismHelper object. +@param aSettings: Refence to CImPop3Settings +@leave KErrNoMemory A memory allocation failed +*/ +CPopAuthCramMd5MechanismHelper* CPopAuthCramMd5MechanismHelper::NewL(const CImPop3Settings& aSettings) + { + CPopAuthCramMd5MechanismHelper* self= new (ELeave) CPopAuthCramMd5MechanismHelper(aSettings); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +Constructor for CPopAuthMechanismHelper +*/ +CPopAuthCramMd5MechanismHelper::CPopAuthCramMd5MechanismHelper(const CImPop3Settings& aSettings) : CPopAuthMechanismHelper(aSettings) + { + } + + +/** +Second phase construction +*/ +void CPopAuthCramMd5MechanismHelper::ConstructL() + { + iMd5Hash = CMD5::NewL(); + } + +/** +Destructor +*/ +CPopAuthCramMd5MechanismHelper::~CPopAuthCramMd5MechanismHelper() + { + delete iMd5Hash; + } + + +/** +Function to form POP3 "AUTH CRAM-MD5" command and to handle base64 encoding of +the challenges and responses as per RFC 2195 +@param aNextMessage: contains response command +*/ +void CPopAuthCramMd5MechanismHelper::GetNextClientMessageL(TDes8& aNextMessage) + { + iNextClientMessage.Zero(); + + if(iInProgress) + { + HBufC8* authbuffer = HBufC8::NewMaxLC(KImMailMaxBufferSize); + TPtr8 authbufferptr = authbuffer->Des(); + HBufC8* authbuffer2 = HBufC8::NewMaxLC(KImMailMaxBufferSize); + TPtr8 authbufferptr2 = authbuffer2->Des(); + HBufC8* authbuffer3 = HBufC8::NewMaxLC(KImMailMaxBufferSize); + TPtr8 authbufferptr3 = authbuffer3->Des(); + + authbufferptr = iLastServerMessage; + // to remove "+ " from the begining of server response + authbufferptr.Delete(0,2); + + //timestamp info now in authbufferptr2 + iEncoder.Decode(authbufferptr,authbufferptr2); + + authbufferptr.Zero(); + authbufferptr3.Zero(); + authbufferptr = iSettings.Password(); + authbufferptr3 = FormSharedSecret(authbufferptr); + authbufferptr.Zero(); + //now authbufferptr and authbufferptr3 contain the shared secret null padded to 64 bytes. + authbufferptr = authbufferptr3; + + TInt i=0; + for (i=0; iReset(); ; + authbufferptr2 = iMd5Hash->Hash(authbufferptr); + + authbufferptr3.Append(authbufferptr2); + + authbufferptr.Zero(); + iMd5Hash->Reset(); + authbufferptr = iMd5Hash->Hash(authbufferptr3); + + // MD5 algorithm ALWAYS returns 16 bytes of data - which will be converted into + // 32 characters; each byte represented by a 2 character hex representation, + // eg 255="ff" + TBuf<32> hexHash; + for (i=0;i<16;i++) + { + hexHash.AppendNumFixedWidth(authbufferptr[i],EHex,2); + } + + authbufferptr3.Zero(); + authbufferptr3.Append(iSettings.LoginName()); + authbufferptr3.Append(_L8(" ")); + authbufferptr3.Append(hexHash); + + iEncoder.Encode(authbufferptr3, iNextClientMessage); + iNextClientMessage.Append(KPop3CrLf); + CleanupStack::PopAndDestroy(3); // authbufferptr3 ,authbufferptr2, authbufferptr + aNextMessage = iNextClientMessage; + } + else + { + iNextClientMessage.Append(KPop3AuthCommand); + iNextClientMessage.Append(KCramMD5Mechanism); + iNextClientMessage.Append(KPop3CrLf); + iInProgress=ETrue; + aNextMessage = iNextClientMessage; + } + } + +/** +FormSharedSecret() +@param aPassword: password +*/ +TPtr8 CPopAuthCramMd5MechanismHelper::FormSharedSecret(TPtr8 aPassword) + { + TPtr8 secret = aPassword; + + if (aPassword.Length() <= KMd5BlockLength) + { + //pad up to 64 bytes with zeros + secret.SetLength(64); + TInt origLen = aPassword.Length(); + TInt lengthToFill = KMd5BlockLength-aPassword.Length(); + for (TInt i = 0; iReset(); + secret = (iMd5Hash->Hash(aPassword)); + } + + return secret; + } + + +/** +To set the last message from server. +@param aPassword: password +*/ +void CPopAuthCramMd5MechanismHelper::SetLastServerMessageL(const TDesC8& aLastMessage, TBool /*aIsMultiLineResponse*/) + { + iLastServerMessage.Set(aLastMessage); + } + + +/** +Constructor +*/ +CPopAuthPlainMechanismHelper::CPopAuthPlainMechanismHelper(const CImPop3Settings& aSettings) : CPopAuthMechanismHelper(aSettings) + { + } + + +/** +Allocates and constructs a CPopAuthPlainMechanismHelper object. +@param aSettings: Refence to CImPop3Settings +@leave KErrNoMemory A memory allocation failed +*/ +CPopAuthPlainMechanismHelper* CPopAuthPlainMechanismHelper::NewL(const CImPop3Settings& aSettings) + { + CPopAuthPlainMechanismHelper* self= new (ELeave) CPopAuthPlainMechanismHelper(aSettings); + return self; + } + + +/** +Function to handle POP3 "AUTH PLIAN" mechanism. +Steps: +1. Get the LoginName from CImPop3Settings +2. Get the Password from CImPop3Settings +3. Add "LoginName","NUL Char" and "Password" in a Buffer +4. Convert the above buffer to BASE64 +@param aNextMessage: Buffer contains BASE64 converted LoginName and Password. +*/ +void CPopAuthPlainMechanismHelper::GetNextClientMessageL(TDes8& aNextMessage) + { + // Build up the un-encoded authorisation string in parts + HBufC8* authString = HBufC8::NewMaxLC(KMaxLengthOfPlainMessage); + TPtr8 authStringPtr = authString->Des(); + + TBuf8<1> nulChar; + nulChar.SetLength(1); + nulChar[0] = 0; + authStringPtr = nulChar; // Start with the NUL + + TPtrC8 loginName = iSettings.LoginName(); + TInt length= Min(loginName.Length(),KMaxLengthOfPlainMessageComponent); + authStringPtr.Append(loginName.Left(length)); + + authStringPtr.Append(nulChar); // Separator between login and password + + length= Min(iSettings.Password().Length(), KMaxLengthOfPlainMessageComponent); + authStringPtr.Append(iSettings.Password().Left(length)); + + // Auth string is now built, encode it + HBufC8* encodedBuf = HBufC8::NewMaxLC(KMaxLengthOfPlainMessageBase64); + TPtr8 encodedBufPtr = encodedBuf->Des(); + + iEncoder.Encode(authStringPtr,encodedBufPtr); + + // Now build the message + iNextClientMessage.Zero(); + iNextClientMessage.Append(KPop3AuthCommand); + iNextClientMessage.Append(KPlainMechanism); + iNextClientMessage.Append(encodedBufPtr); + iNextClientMessage.Append(KPop3CrLf); + + aNextMessage = iNextClientMessage; + + CleanupStack::PopAndDestroy(2, authString); // encodedBuf, authString + } + +/** +To set the last message from server. +@param aPassword: password +*/ +void CPopAuthPlainMechanismHelper::SetLastServerMessageL(const TDesC8& /*aLastMessage*/, TBool /*aIsMultiLineResponse*/) + { + //iLastServerMessage.Set(aLastMessage); + } + +/** +Constructor +*/ +CPopAuthLoginMechanismHelper::CPopAuthLoginMechanismHelper(const CImPop3Settings& aSettings) : CPopAuthMechanismHelper(aSettings) + { + } + +/** +Allocates and constructs a CPopAuthLoginMechanismHelper object. +@param aSettings: Refence to CImPop3Settings +@leave KErrNoMemory A memory allocation failed +*/ +CPopAuthLoginMechanismHelper* CPopAuthLoginMechanismHelper::NewL(const CImPop3Settings& aSettings) + { + CPopAuthLoginMechanismHelper* self= new (ELeave) CPopAuthLoginMechanismHelper(aSettings); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +Destructor +*/ +CPopAuthLoginMechanismHelper::~CPopAuthLoginMechanismHelper() + { + delete iBase64LoginName; + delete iBase64Password; + } + +/** +SecondPhase construction +*/ +void CPopAuthLoginMechanismHelper::ConstructL() + { + // length of LoginName in base 64 + 2 for CRLF + TInt len=(((iSettings.LoginName().Length()/3)+1)*4)+2; + iBase64LoginName=HBufC8::NewL(len); + TPtr8 authString(iBase64LoginName->Des()); + iEncoder.Encode(iSettings.LoginName(),authString); + authString.Append(KPop3CrLf); + + // length of Password in base 64 + 2 for CRLF + len=(((iSettings.Password().Length()/3)+1)*4)+2; + iBase64Password=HBufC8::NewL(len); + authString.Set(iBase64Password->Des()); + iEncoder.Encode(iSettings.Password(),authString); + authString.Append(KPop3CrLf); + } + + +/** +Function to handle POP3 "AUTH LOGIN" mechanism. +@param aNextMessage: aNextMessage contains BASE64 converted LoginName/Password. +*/ +void CPopAuthLoginMechanismHelper::GetNextClientMessageL(TDes8& aNextMessage) + { + iNextClientMessage.Zero(); + switch (iState) + { + case ESendingAuth: + iNextClientMessage=KPop3AuthLoginCommand; + break; + case ESendingLoginName: + iNextClientMessage=*iBase64LoginName; + break; + case ESendingPassword: + iNextClientMessage=*iBase64Password; + break; + default: + Panic(EPopInvalidState); + break; + } + aNextMessage=iNextClientMessage; + } + +void CPopAuthLoginMechanismHelper::SetLastServerMessageL(const TDesC8& aLastMessage, TBool /*aIsMultiLineResponse*/) + { + HBufC8* decodedMessage = NULL; + TInt lastMessageLength = aLastMessage.Length(); + + // Decode the POP response from the Base64 original + if (lastMessageLength > 0) + { + decodedMessage = HBufC8::NewLC(lastMessageLength); // already on stack + // Get pointer to response minus the "+ " at the start + TPtrC8 response = aLastMessage.Right(lastMessageLength - 2); + TPtr8 destination = decodedMessage->Des(); + iEncoder.Decode(response, destination); + } + switch (iState) + { + case ESendingAuth: + if (decodedMessage) + { + // Match against 'username*' + if (decodedMessage->Des().MatchF(KPop3AuthBase64StringUsername) == KErrNotFound) + { + User::Leave(KErrNotSupported); + } + iEncoder.Initialise(); + iState = ESendingLoginName; + } + else + { + User::Leave(KErrNotSupported); + } + break; + case ESendingLoginName: + if (decodedMessage) + { + // Match against 'password*' + if (decodedMessage->Des().MatchF(KPop3AuthBase64StringPassword) == KErrNotFound) + { + User::Leave(KErrNotSupported); + } + iEncoder.Initialise(); + iState = ESendingPassword; + } + else + { + User::Leave(KErrNotSupported); + } + break; + case ESendingPassword: + default: + User::Leave(KErrNotSupported); + break; + } + + if (decodedMessage) + { + CleanupStack::PopAndDestroy(decodedMessage); + } + } +