--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/popservermtm/src/cpopsaslauthhelper.cpp Fri Jun 04 10:25:39 2010 +0100
@@ -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 <e32des8.h>
+#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; i<KMd5BlockLength; i++)
+ {
+ authbufferptr[i] ^= 0x36; //ipad
+ authbufferptr3[i] ^= 0x5c; //opad
+ }
+
+ authbufferptr.Append(authbufferptr2);
+
+ iMd5Hash->Reset(); ;
+ 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; i<lengthToFill; i++)
+ {
+ secret[origLen+i]=0x00;
+ }
+ }
+ else
+ {
+ //make shared secret the Digest of the password
+ secret.Zero();
+ iMd5Hash->Reset();
+ 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);
+ }
+ }
+