--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/authenticationservices/authenticationserver/source/server/authserver.cpp Tue Nov 24 09:06:03 2009 +0200
@@ -0,0 +1,2011 @@
+/*
+* 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 the License "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:
+* CAuthServer implementation
+*
+*/
+
+
+/**
+ @file
+*/
+
+#include <s32mem.h>
+#include <s32file.h>
+#include <ecom/ecom.h>
+#include <pbedata.h>
+#include <scs/cleanuputils.h>
+#include "authserver_impl.h"
+#include "authtransaction.h"
+#include "authserver/aspubsubdefs.h"
+#include "authserverutil.h"
+
+using namespace AuthServer;
+
+const TUint CAuthServer::iRangeCount = KPolicyRanges;
+
+const TInt CAuthServer::iRanges[KPolicyRanges] =
+ {
+ 0,
+ CScsServer::EBaseSession,
+ CScsServer::EBaseSession |ERequireNoCapabilities, // accessible by all clients.
+ CScsServer::EBaseSession |ERequireReadUserData, // accessible by ReadUserData clients only.
+ CScsServer::EBaseSession |ERequireWriteUserData, // accessible by WriteUserData clients only.
+ CScsServer::EBaseSession |ERequireReadDeviceData, // accessible by ReadDeviceData clients only.
+ CScsServer::EBaseSession |ERequireWriteDeviceData, // accessible by WriteDeviceData clients only.
+ CScsServer::EBaseSession |ERequireTrustedUi, // accessible by TrustedUi clients only.
+ CScsServer::EBaseSession |ERequireReadDeviceAndUserData, // accessible by clients with both
+ // ReadUserData and ReadDeviceData.
+ CScsServer::EBaseSession |ERequireCustomCheck, // Require custom check.
+ CScsServer::EBaseSession |ELastService,
+ CScsServer::EBaseMustAllow // SCS Internal.
+ };
+
+const TUint8 CAuthServer::iElementsIndex[iRangeCount] =
+ {
+ CPolicyServer::ENotSupported,
+ CPolicyServer::EAlwaysPass,
+ 0, // all clients can have access
+ 1, // ReadUserData clients only
+ 2, // WriteUserData clients only
+ 3, // ReadDeviceData
+ 4, // WriteDeviceData
+ 5, // trusted ui
+ 6, // ReadUserData and ReadDeviceData
+ CPolicyServer::ECustomCheck, // custom check
+ CPolicyServer::EAlwaysPass,
+ CPolicyServer::EAlwaysPass,
+ };
+
+const CPolicyServer::TPolicyElement CAuthServer::iPolicyElements[] =
+ {
+ {_INIT_SECURITY_POLICY_C1(ECapability_None), CPolicyServer::EFailClient},
+ {_INIT_SECURITY_POLICY_C1(ECapabilityReadUserData), CPolicyServer::EFailClient},
+ {_INIT_SECURITY_POLICY_C1(ECapabilityWriteUserData), CPolicyServer::EFailClient},
+ {_INIT_SECURITY_POLICY_C1(ECapabilityReadDeviceData), CPolicyServer::EFailClient},
+ {_INIT_SECURITY_POLICY_C1(ECapabilityWriteDeviceData), CPolicyServer::EFailClient},
+ {_INIT_SECURITY_POLICY_C1(ECapabilityTrustedUI), CPolicyServer::EFailClient},
+ {_INIT_SECURITY_POLICY_C2(ECapabilityReadDeviceData, ECapabilityReadUserData), CPolicyServer::EFailClient},
+ };
+
+const CPolicyServer::TPolicy CAuthServer::iPolicy =
+ {
+ CPolicyServer::EAlwaysPass, // so that any client can connect
+ iRangeCount,
+ iRanges,
+ iElementsIndex,
+ iPolicyElements,
+ };
+
+_LIT_SECURITY_POLICY_S0(CAuthServer::iPropertyWritePolicy, KAuthServerSecureId.iUid);
+_LIT_SECURITY_POLICY_PASS(CAuthServer::iPropertyReadPolicy);
+
+
+inline CAuthServer::CAuthServer(CActive::TPriority aPriority)
+ :CScsServer(TVersion(1,0,0), iPolicy, aPriority)
+ {}
+
+CAuthServer* CAuthServer::NewLC(CActive::TPriority aPriority)
+ {
+ CAuthServer* self = new(ELeave) CAuthServer(aPriority);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+void CAuthServer::ConstructL()
+ {
+ // Delay starting of shutdown timer till we finish construction since
+ // loading of ECOM plugins takes a while
+ CScsServer::ConstructL(0);
+ TInt r;
+ StartL(KAuthServerName);
+ r = iFs.Connect();
+ User::LeaveIfError(r);
+ r = iFs.CreatePrivatePath(RFs::GetSystemDrive());
+ User::LeaveIfError(r);
+
+ // Retrieve the key size to be used for protection keys
+ CPBEncryptElement* pbee = CPBEncryptElement::NewLC(_L(""));
+ iKeySize = pbee->EncryptionData().AuthData().Key().Size();
+ CleanupStack::PopAndDestroy(pbee);
+ iAuthRepository = CAuthRepository::NewL();
+ iAuthDb2 = CAuthDb2::NewL(iFs);
+ iPluginMgr = CPluginMgr::NewL();
+ iPluginObserver = CPluginObserver::NewL(*iPluginMgr);
+ iEvaluator = CEvaluator::NewL(this,this);
+ iTrainingMgr = new (ELeave) CTrainingMgr(*iPluginMgr, *iAuthDb2, *iAuthRepository);
+ TUid clientSid = {0};
+ iParams = CAuthParams::NewL(0,
+ EFalse,
+ clientSid,
+ EFalse,
+ KNullDesC());
+ CreatePropertiesL();
+ FirstStartL();
+
+ // Construction complete, now start the shutdown timer
+ CScsServer::EnableShutdownTimerL(AuthServer::KDefaultShutdownDelay);
+ }
+
+
+CPolicyServer::TCustomResult CAuthServer::CustomSecurityCheckL(const RMessage2& aMessage,
+ TInt& /*aAction*/, TSecurityInfo& aMissing)
+ {
+ TInt KAuthParams = 1;
+ TInt paramsLen = aMessage.GetDesLength(KAuthParams);
+
+ if(paramsLen != KErrBadDescriptor)
+ {
+ //Create a buffer.
+ HBufC8* buffer = HBufC8::NewLC(paramsLen);
+ TPtr8 bufDes(buffer->Des());
+ aMessage.ReadL(EIpcArgument1, bufDes);
+
+ //Internalize the params object.
+ RDesReadStream readStream(*buffer);
+ CleanupClosePushL(readStream);
+ iParams->InternalizeL(readStream);
+ CleanupStack::PopAndDestroy(2, buffer);
+ }
+
+ TBool clientKey = iParams->iClientKey;
+ TBool withString = iParams->iWithString;
+ TInt clientSid = iParams->iClientSid.iUid;
+
+ if((!clientKey || withString || ((clientSid != aMessage.SecureId()) && clientSid != 0 )) && !(aMessage.HasCapability(ECapabilityReadUserData)))
+ {
+ // Missing ReadUserData capability.
+ aMissing.iCaps.Set(ECapabilityReadUserData);
+ return CPolicyServer::EFail;
+ }
+
+ else
+ {
+ return CPolicyServer::EPass;
+ }
+ }
+
+/**
+ * Creates and initialises the two AuthServer properties -
+ * KUidAuthServerLastAuth and KUidAuthServerAuthChangeEvent.
+ *
+ **/
+void CAuthServer::CreatePropertiesL()
+ {
+ // KUidAuthServerLastAuth
+ TInt err1 = iAuthProperty.Define(KUidAuthServerLastAuth, RProperty::EText,
+ iPropertyReadPolicy, iPropertyWritePolicy,
+ sizeof(TLastAuth));
+
+ User::LeaveIfError(iAuthProperty.Attach(KAuthServerSecureId,
+ KUidAuthServerLastAuth));
+
+
+ // KUidAuthServerAuthChangeEvent
+ TInt err2 = iAuthEventProperty.Define(KUidAuthServerAuthChangeEvent,
+ RProperty::EInt,
+ iPropertyReadPolicy,
+ iPropertyWritePolicy);
+
+ User::LeaveIfError(iAuthEventProperty.Attach(KAuthServerSecureId,
+ KUidAuthServerAuthChangeEvent));
+
+ if (err1 == KErrNone || err2 == KErrNone )
+ {
+ ClearPropertiesL();
+ }
+ }
+
+void CAuthServer::ClearPropertiesL()
+ {
+ TLastAuth lastAuth;
+ TPckg<TLastAuth> authPckg(lastAuth);
+ User::LeaveIfError(iAuthProperty.Set(authPckg));
+ User::LeaveIfError(iAuthEventProperty.Set(KUnknownIdentity));
+ }
+
+
+/**
+ * Checks the number of identities in the database and iff zero asks the
+ * training mgr to register the first identity.
+ *
+ * @leave KErrAuthServerCanNotCreateFirstId if the first identity cannot
+ * be created
+ **/
+void CAuthServer::FirstStartL()
+ {
+ TInt numIds = iAuthDb2->NumIdentitiesL();
+ if (numIds == 0)
+ {
+ TIdentityId id = 0;
+ TPckg<TIdentityId> idPkg(id);
+ TRandom::RandomL(idPkg);
+
+ CProtectionKey* key = CProtectionKey::NewL(iKeySize);
+ if (!iTrainingMgr->RegisterFirstIdentityL(id, *key))
+ {
+ User::Panic(KAuthServerShortName, EPanicNoFirstStartPlugin);
+ }
+ }
+ }
+
+CAuthServer::~CAuthServer()
+ {
+ delete iAuthRepository;
+ delete iAuthTransaction;
+
+ delete iTrainingMgr;
+ delete iLastIdentity;
+ delete iEvaluator;
+ delete iPluginMgr;
+ delete iPluginObserver;
+ delete iParams;
+ if (iAuthDb2 != 0)
+ {
+ iAuthDb2->CompactIfRequired();
+ delete iAuthDb2;
+ }
+
+ iFs.Close();
+ REComSession::FinalClose();
+ }
+
+
+/**
+ * Creates a new session
+ * @param aClientVersion the version of the connecting client
+ * @param aMessage the connect message
+ */
+CScsSession* CAuthServer::DoNewSessionL(const RMessage2& /*aMessage*/)
+ {
+ return CAuthServerSession::NewL(*this);
+ }
+
+
+/**
+ * Returns the last identity to be authenticated within the period
+ * currTime to currTime-timeout.
+ *
+ * @param currTime the current universal time
+ *
+ * @param timeout the number of seconds within which the last
+ * authentication should have been made
+ *
+ * @return 0 if there has been no previous authentications either in the
+ * server lifetime or within the timeout period.
+ *
+ * @return a pointer to the cached identity object
+ **/
+CIdentity* CAuthServer::CachedIdentity( const TTimeIntervalSeconds& aTimeOut)
+ {
+ // process request
+ TTime currentTime;
+ if(currentTime.UniversalTimeSecure() == KErrNoSecureTime)
+ {
+ // Fall back to nonsecure time.
+ currentTime.UniversalTime();
+ }
+
+ CIdentity* id = 0;
+
+ TTimeIntervalSeconds timeSinceLast;
+ currentTime.SecondsFrom(iLastAuthTime, timeSinceLast);
+
+ if (timeSinceLast.Int() >= 0 && timeSinceLast < aTimeOut)
+ {
+ id = iLastIdentity;
+ }
+
+ return id;
+ }
+
+
+
+/**
+ *
+ * @param aMessage the message to process
+ **/
+void CAuthServer::DeauthenticateL(const RMessage2& aMessage)
+ {
+ if (ServerBusy())
+ {
+ aMessage.Complete(KErrServerBusy);
+ return;
+ }
+
+ delete iLastIdentity;
+ iLastIdentity = 0;
+ iLastAuthTime = 0L;
+
+ ClearPropertiesL();
+ aMessage.Complete(KErrNone);
+ }
+
+HBufC* CAuthServer::StringOrNullLC(TBool aReturnString, TIdentityId aId)
+ {
+ HBufC* str = 0;
+ if (aReturnString)
+ {
+ TRAPD(err, str = iAuthDb2->DescriptionL(aId));
+ if (!err)
+ {
+ CleanupStack::PushL(str);
+ }
+
+ }
+ if (str == 0)
+ {
+ str = HBufC::NewLC(0);
+ }
+ return str;
+ }
+
+void CAuthServer::AuthenticateL(const RMessage2& aMessage)
+ {
+ if (ServerBusy())
+ {
+ aMessage.Complete(KErrServerBusy);
+ return;
+ }
+
+ TInt KAuthParams = 1;
+ TInt paramsLen = aMessage.GetDesLength(KAuthParams);
+
+ if(paramsLen != KErrBadDescriptor)
+ {
+ //Create a buffer.
+ HBufC8* buffer = HBufC8::NewLC(paramsLen);
+ TPtr8 bufDes(buffer->Des());
+
+ aMessage.ReadL(EIpcArgument1, bufDes);
+
+ //Internalize the params object.
+ RDesReadStream readStream(*buffer);
+ CleanupClosePushL(readStream);
+ iParams->InternalizeL(readStream);
+ CleanupStack::PopAndDestroy(2, buffer);
+ }
+
+ CIdentity* id = CachedIdentity(iParams->iTimeout);
+
+ if (id == 0) // no valid cache available
+ {
+ const TInt KAuthExprParam = 0;
+
+ // reconstruct the authentication expression
+ TInt extLen = aMessage.GetDesLengthL(KAuthExprParam);
+ HBufC8* extSrv = HBufC8::NewLC(extLen);
+ TPtr8 desSrv8 = extSrv->Des();
+ aMessage.ReadL(KAuthExprParam, desSrv8);
+
+ RDesReadStream drs(desSrv8);
+ CAuthExpression* authExpr = CAuthExpressionImpl::NewL(drs);
+ // don't need the stream any more, so free it
+ CleanupStack::PopAndDestroy(extSrv);
+ CleanupStack::PushL(authExpr);
+
+ const CAuthExpressionImpl* expr = static_cast<const CAuthExpressionImpl*>(authExpr);
+
+ iAuthTransaction = CAuthTransaction::NewL(aMessage,
+ iParams->iClientKey,
+ iParams->iClientSid.iUid,
+ iParams->iWithString,
+ *iParams->iClientMessage,
+ expr);
+ CleanupStack::Pop(authExpr);
+
+ iEvaluator->Evaluate(expr);
+
+ return;
+ }
+
+ else if (iParams->iClientKey && (id->Id() != KUnknownIdentity))
+ {
+
+ HBufC* str = StringOrNullLC(iParams->iWithString, id->Id());
+ CIdentity* id2 = 0;
+
+ TInt clientId = aMessage.SecureId();
+
+ if(iParams->iClientSid.iUid != 0)
+ {
+ clientId = iParams->iClientSid.iUid;
+ }
+
+ id2 = CIdentity::NewL(id->Id(), id->Key().ClientKeyL(clientId), str);
+
+ CleanupStack::Pop(str);
+ CleanupStack::PushL(id2);
+ // id pointer already stored as iLastIdentity
+ id = id2;
+ }
+
+ CompleteAuthenticationL(aMessage, id);
+
+ if (id != iLastIdentity)
+ {
+ // only clean up the allocated id if it has not been transferred to us.
+ CleanupStack::PopAndDestroy(id);
+ }
+
+ }
+
+// -------- plugin lists --------
+
+
+/**
+ Build an array containing descriptions for the
+ plugins available on the system and send it to
+ the client.
+
+ @param aMessage Message describing client
+ request.
+ @param aFilter Function which decides whether
+ or not to include a plugin in the
+ list.
+ */
+void CAuthServer::FilterPluginsL(
+ const RMessage2& aMessage, CAuthServer::TInterfaceFilter aFilter)
+
+ {
+ RCPointerArray<const CPluginDesc> descs;
+ GetDescriptionsFromEComLC(aFilter, descs);
+ AuthServerUtil::SendDataPointerArrayL(aMessage, descs, 0);
+ CleanupStack::PopAndDestroy(&descs);
+ }
+
+
+/**
+ Populate the supplied array with plugin descriptions generated
+ from the available ECOM plugins.
+
+ @param aFilter Predicate function decides whether or not
+ to include each plugin in the list.
+ @param aDescs Array to populate. When this function is
+ called, any existing entries are removed.
+ If this function leaves then any entries are
+ removed from the array. On success, the
+ array is on the cleanup stack.
+ */
+void CAuthServer::GetDescriptionsFromEComLC(
+ CAuthServer::TInterfaceFilter aFilter,
+ RCPointerArray<const CPluginDesc>& aDescs)
+ {
+ aDescs.Reset();
+ CleanupClosePushL(aDescs);
+
+ // ownership of the data pointed by this array is with
+ // the plugin manager.
+ const RPointerArray<CImplementationInformation>& implInfo = iPluginMgr->ImplementationsL();
+ TInt implCount = implInfo.Count();
+
+ for (TInt i = 0; i < implCount; ++i)
+ {
+ // avoid RVCT warning C2874W: pi may be used before being set
+ CAuthPluginInterface* pi = 0;
+
+ TRAPD(r, pi = iPluginMgr->ImplementationL(i));
+
+ // skip plugins which are not available
+ if (KErrNone != r)
+ continue;
+
+ if (! (this->*aFilter)(*pi))
+ {
+ continue;
+ }
+
+ // get training status from db
+ TAuthTrainingStatus ts = iAuthDb2->PluginStatusL(pi->Id());
+
+ CPluginDesc* pd = CPluginDesc::NewL(
+ pi->Id(), pi->Name(), pi->Type(),
+ ts, pi->MinEntropy(),
+ pi->FalsePositiveRate(), pi->FalseNegativeRate() );
+
+ CleanupStack::PushL(pd);
+ aDescs.AppendL(pd);
+ CleanupStack::Pop(pd);
+ }
+
+ }
+
+
+
+/**
+ Build an array containing plugin descriptions for
+ each plugin which is available on the system, and
+ copy this into the client's space.
+
+ @param aMessage Client message. This contains
+ the client-side buffer.
+ */
+void CAuthServer::PluginsL(const RMessage2& aMessage)
+ {
+ FilterPluginsL(aMessage, &CAuthServer::FilterAllPlugins);
+ }
+
+
+/**
+ Predicate function used by PluginsL.. This accepts all plugins.
+
+ @return Always ETrue.
+ @see PluginsL
+ */
+TBool CAuthServer::FilterAllPlugins(const CAuthPluginInterface&)
+ {
+ return ETrue;
+ }
+
+
+/**
+ *
+ * @param aMessage the message to process
+ **/
+void CAuthServer::ActivePluginsL(const RMessage2& aMessage)
+ {
+ FilterPluginsL(aMessage, &CAuthServer::FilterActivePlugins);
+ }
+
+
+/**
+ * Indicates a plugin is active.
+ *
+ * @param aInterface the auth plugin interface to check
+ * @return true if aInterface.IsActive()
+ **/
+TBool CAuthServer::FilterActivePlugins(const CAuthPluginInterface& aInterface)
+ {
+ return aInterface.IsActive();
+ }
+
+
+/**
+ Build an array which containing plugin descriptions
+ for each plugin which is available and has the type
+ supplied by the client.
+
+ @param aMessage Client message. This contains
+ the plugin type and points to the
+ client-side buffer.
+ */
+void CAuthServer::PluginsByTypeL(const RMessage2& aMessage)
+ {
+ iFilterType = static_cast<TAuthPluginType>(aMessage.Int1());
+ FilterPluginsL(aMessage, &CAuthServer::FilterPluginsByType);
+ }
+
+
+/**
+ Predicate which checks whether the supplied description should
+ be included in the result list.
+
+ The type to filter on is stored as a member variable.
+
+ @param aInterface Interface to check.
+ @return Zero if interface's type does not match
+ filter type, non-zero otherwise.
+ @see PluginsByTypeL
+ */
+TBool CAuthServer::FilterPluginsByType(const CAuthPluginInterface& aInterface)
+ {
+ return (aInterface.Type() == iFilterType);
+ }
+
+
+/**
+ Build an array which contains plugin descriptions
+ for each plugin which has the supplied training status,
+ and write that array into the caller's space.
+
+ @param aMessage Client message contains the status
+ to filter on.
+ */
+void CAuthServer::PluginsByTrainingL(const RMessage2& aMessage)
+ {
+ iFilterTraining = static_cast<TAuthTrainingStatus>(aMessage.Int1());
+ FilterPluginsL(aMessage, &CAuthServer::FilterPluginsByTraining);
+ }
+
+
+/**
+ Predicate checks if the supplied interface describes
+ a plugin with the required training status.
+
+ @param aInterface Interface to check.
+ @return Zero if interface's training status
+ does not match the filter status;
+ non-zero otherwise.
+ @see PluginsByTrainingL
+ */
+TBool
+CAuthServer::FilterPluginsByTraining(const CAuthPluginInterface& aInterface)
+ {
+ // training status is stored in the db, not in the ECOM interface.
+ // If this function returns non-zero, the same request will be made
+ // on the DB to get the status again to construct the description.
+ // This is suboptimal, and could be improved by special-casing the
+ // training filter if required.
+
+ TAuthTrainingStatus ts = EAuthUntrained;
+ TRAPD(err, ( ts = iAuthDb2->PluginStatusL(aInterface.Id())));
+ return err == KErrNone ? ts == iFilterTraining : EFalse;
+ }
+
+
+/**
+ Populate a client-side array with the set of identities.
+
+ @param aMessage Client message which points to the
+ user-side array.
+ */
+void CAuthServer::IdentitiesL(const RMessage2& aMessage)
+ {
+ RArray<TIdentityId> ids;
+ iAuthDb2->IdentitiesL(ids);
+ CleanupClosePushL(ids);
+ AuthServerUtil::SendDataArrayL(aMessage, ids, 0);
+ CleanupStack::PopAndDestroy(&ids);
+ }
+/**
+ Retrieve the preferred plugin for the specified type
+
+ @param aMessage Client message
+ */
+void CAuthServer::PreferredTypePluginL(const RMessage2& aMessage)
+ {
+ TPluginId id =
+ iAuthDb2->PreferredPluginL(static_cast<TAuthPluginType>(aMessage.Int0()));
+
+ TPckg<TPluginId> idPckg(id);
+ aMessage.WriteL(1, idPckg);
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+ Set the preferred plugin for the specified type
+
+ @param aMessage Client message
+ */
+void CAuthServer::SetPreferredTypePluginL(const RMessage2& aMessage)
+ {
+ TInt err = KErrArgument;
+ TAuthPluginType pluginType = static_cast<TAuthPluginType>(aMessage.Int0());
+ TPluginId pluginId = aMessage.Int1();
+
+ if (iPluginMgr->PluginL(pluginId)->Type() == pluginType)
+ {
+ iAuthDb2->SetPreferredPluginL(pluginType,pluginId);
+ err = KErrNone;
+ }
+ aMessage.Complete(err);
+ }
+
+/**
+ Retrieve description for a supplied identity.
+
+ @param aMessage Client message which contains the
+ identity and points to a client-side
+ buffer, to which the description will
+ be copied.
+ */
+void CAuthServer::IdentityStringL(const RMessage2& aMessage)
+ {
+ HBufC* desc = iAuthDb2->DescriptionL(aMessage.Int1());
+ CleanupStack::PushL(desc);
+ aMessage.WriteL(EIpcArgument0, *desc);
+ CleanupStack::PopAndDestroy(desc);
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+ Retrieve description & id for all identities.
+
+ @param aMessage Client message which contains the
+ identity and points to a client-side
+ buffer, to which the description will
+ be copied.
+ */
+void CAuthServer::IdentitiesWithStringL(const RMessage2& aMessage)
+ {
+ RIdAndStringArray result;
+
+ iAuthDb2->IdentitiesWithDescriptionL(result);
+ CleanupClosePushL(result);
+
+ AuthServerUtil::SendDataPointerArrayL(aMessage,result,0);
+ CleanupStack::PopAndDestroy(&result);
+ }
+
+/**
+ *
+ * @param aMessage the message to process
+ **/
+void CAuthServer::SetIdentityStringL(const RMessage2& aMessage)
+ {
+ HBufC* str = HBufC::NewLC(aMessage.GetDesLengthL(1));
+ TPtr strDes = str->Des();
+ TInt err = aMessage.Read(1, strDes);
+
+ if (err == KErrNone)
+ {
+ iAuthDb2->SetDescriptionL(aMessage.Int0(), *str);
+ }
+ CleanupStack::PopAndDestroy(str);
+ aMessage.Complete(err);
+ }
+
+
+
+/**
+ Copies the authentication alias list obtained using
+ ListAliasL() method to a client-side buffer .
+
+ @param aMessage Client message which points to a client-side
+ buffer, to which the authentication strength
+ list will be copied.
+ */
+
+void CAuthServer::ListAuthAliasesL(const RMessage2& aMessage)
+ {
+ RPointerArray<HBufC> aliasList;
+ CleanupResetAndDestroyPushL(aliasList);
+
+ //get the list of available authentication strengths from the cenrep file.
+ iAuthRepository->ListAliasL(aliasList);
+
+ AuthServerUtil::SendDataPointerArrayL(aMessage, aliasList, EIpcArgument0);
+ CleanupStack::PopAndDestroy(&aliasList);
+ }
+
+/**
+ Resolves any alias occurrence in the expression to its corresponding
+ value.
+
+ @param aMessage Client message which contains the free form
+ authentication expression and points to a
+ client-side buffer, to which the string will
+ be copied.
+
+ */
+void CAuthServer::ResolveExpressionL(const RMessage2& aMessage)
+ {
+
+ // the auth strength passed by the client.
+ TInt length = aMessage.GetDesLength(EIpcArgument1);
+ HBufC* clientExpression = HBufC::NewLC(length);
+ TPtr clientExprPtr(clientExpression->Des());
+
+ aMessage.ReadL(EIpcArgument1, clientExprPtr);
+
+ RBuf resultantString;
+ CleanupClosePushL(resultantString);
+
+ resultantString.CreateL(KDefaultBufferSize/2);
+
+ // get the alias list
+ RPointerArray<HBufC> aliasList;
+ CleanupResetAndDestroyPushL(aliasList);
+
+ //get the list of available authentication strength from the cenrep file.
+ iAuthRepository->ListAliasL(aliasList);
+
+
+ // parse the client side expression to see whether there
+ // are any alias, if present process them accordingly.
+ TLex input(clientExprPtr);
+
+ // append the open bracket first so that the entire expression is within brackets.
+ resultantString.Append(KOpenBracket);
+
+ for(TPtrC token = input.NextToken(); token.Size() > 0; token.Set(input.NextToken()))
+ {
+
+ if( token.CompareF(KOpenBracket) == 0 ||
+ token.CompareF(KCloseBracket) == 0 ||
+ token.CompareF(KAuthOpAnd) == 0 ||
+ token.CompareF(KAuthOpOr) == 0
+ )
+ {
+ int reqdBufferLength = resultantString.Length() + token.Length();
+
+ if(resultantString.MaxLength() < reqdBufferLength)
+ {
+ if(resultantString.MaxLength() == 0)
+ {
+ resultantString.Close();
+ }
+ resultantString.ReAllocL(reqdBufferLength);
+ }
+
+ resultantString.Append(token);
+ }
+ else if(token.CompareF(KAuthBiometric) == 0 ||
+ token.CompareF(KAuthDefault) == 0 ||
+ token.CompareF(KAuthKnowledge) == 0 ||
+ token.CompareF(KAuthToken) == 0 ||
+ token.CompareF(KAuthPerformance) == 0 )
+ {
+ RBuf tokenType;
+ CleanupClosePushL(tokenType);
+ TokenizeStringL(token, tokenType);
+ int reqdBufferLength = resultantString.Length() + tokenType.Length();
+ if(resultantString.MaxLength() < reqdBufferLength)
+ {
+ if(resultantString.MaxLength() == 0)
+ {
+ resultantString.Close();
+ }
+ resultantString.ReAllocL(reqdBufferLength);
+ }
+
+ resultantString.Append(tokenType);
+ CleanupStack::PopAndDestroy(&tokenType);
+ }
+ else
+ {
+ // should not be a number
+ TInt32 val = 0;
+ TLex value(token);
+ if(value.Val(val) == KErrNone)
+ {
+ RBuf tokenPluginId;
+ CleanupClosePushL(tokenPluginId);
+ TokenizeStringL(token, tokenPluginId);
+ int reqdBufferLength = resultantString.Length() + tokenPluginId.Length();
+ if(resultantString.MaxLength() < reqdBufferLength)
+ {
+ if(resultantString.MaxLength() == 0)
+ {
+ resultantString.Close();
+ }
+ resultantString.ReAllocL(reqdBufferLength);
+ }
+ resultantString.Append(tokenPluginId);
+ CleanupStack::PopAndDestroy(&tokenPluginId);
+ continue;
+ }
+
+ RBuf aliasString;
+ CleanupClosePushL(aliasString);
+
+ // this is a alias value which should be processed
+ ResolveAliasL(token, aliasList, aliasString);
+ int reqdBufferLength = resultantString.Length() + aliasString.Length();
+ if(resultantString.MaxLength() < reqdBufferLength)
+ {
+ if(resultantString.MaxLength() == 0)
+ {
+ resultantString.Close();
+ }
+ resultantString.ReAllocL(reqdBufferLength);
+ }
+ resultantString.Append(aliasString);
+ CleanupStack::PopAndDestroy(&aliasString);
+ }
+ }
+
+ int reqdBufferLength = resultantString.Length() + KCloseBracket().Length();
+
+ if(resultantString.MaxLength() < reqdBufferLength)
+ {
+ if(resultantString.MaxLength() == 0)
+ {
+ resultantString.Close();
+ }
+ resultantString.ReAllocL(reqdBufferLength);
+ }
+
+ // append the close bracket in the end so that the entire expression is within brackets.
+ resultantString.Append(KCloseBracket);
+
+ //see if we have enough space on the client.
+ length = resultantString.Length();
+ if(aMessage.GetDesMaxLengthL(EIpcArgument0) < length)
+ {
+ TPckg<TInt> lenPckg(length);
+ aMessage.WriteL(EIpcArgument0, lenPckg);
+ aMessage.Complete(KErrOverflow);
+ }
+
+ aMessage.WriteL(EIpcArgument0, resultantString);
+ CleanupStack::PopAndDestroy(3, clientExpression); //aliasList, resultantString.
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+ Inserts space in between operators and inserts brackets for as
+ expression
+
+ @param aStringToBeProcessed string to be tokenized.
+ @param aResultantString would contain the final tokenized
+ string
+ */
+
+void CAuthServer::TokenizeStringL( const TDesC& aStringToBeProcessed, RBuf& aResultantString )
+ {
+ TInt newLength = aStringToBeProcessed.Length() + 2;
+ HBufC* resultantBuffer = HBufC::NewLC(newLength);
+ TPtr resultantBufPtr(resultantBuffer->Des());
+ resultantBufPtr.Append(KOpenBracket);
+ resultantBufPtr.Append(aStringToBeProcessed);
+ TInt index = resultantBufPtr.Length();
+ resultantBufPtr.Append(KCloseBracket);
+
+ CAuthExpressionImpl::InsertSpaceBetweenOperatorsL(*resultantBuffer, aResultantString);
+ CleanupStack::PopAndDestroy(resultantBuffer);
+
+ }
+
+/**
+ Retrieves the alias string corresponding to the
+ supplied authentication strength.
+
+ @param aMessage Client message which contains the
+ authentication strength and points to a
+ client-side buffer, to which the alais
+ string will be copied.
+
+ */
+
+void CAuthServer::ResolveAliasL(const TDesC& aAliasName,
+ RPointerArray<HBufC>& aAliasList,
+ RBuf& aResultantString)
+ {
+ HBufC* aliasString = HBufC::NewLC(KDefaultBufferSize/2);
+ TPtr aliasStringPtr(aliasString->Des());
+
+ TBool aliasFound = EFalse;
+
+ // find a match for the client supplied alias from the aliasList.
+ for(TInt i = 0; i < aAliasList.Count(); ++i)
+ {
+ if(aAliasName.CompareF(*aAliasList[i]) != 0)
+ {
+ continue;
+ }
+
+ aliasFound = ETrue;
+ // retrieve the alias string corresponding to a given authentication strength.
+ iAuthRepository->GetAliasDefinitionL(i, aliasStringPtr);
+ if(aliasStringPtr.Length() == 0)
+ {
+ User::Leave(KErrAuthStrengthAliasNotDefined);
+ }
+
+ // enclose the alias string within brackets.This would facilitate easy evaluation
+ // of the alias string expression.
+ TInt newLength = aliasStringPtr.Length() + 2;
+ if(newLength > aliasStringPtr.MaxLength())
+ {
+ aliasString->ReAllocL(newLength);
+ }
+
+ aliasStringPtr.Insert(0, KOpenBracket);
+ TInt index = aliasStringPtr.Length();
+ aliasStringPtr.Insert(index, KCloseBracket);
+
+ // tokenize aliasString, to facilitate parsing using TLex.
+ CAuthExpressionImpl::InsertSpaceBetweenOperatorsL(*aliasString, aResultantString);
+
+ if(aResultantString.Length() > aliasStringPtr.MaxLength())
+ {
+ aliasString = aliasString->ReAllocL(aResultantString.Length());
+ }
+
+ aliasStringPtr.Copy(aResultantString);
+ aResultantString.Close();
+
+ // aliasString contains an alias, so process it until we end up
+ // with an expression containing plugin Id or plugin Type or a combination of both.
+ ProcessAliasStringL(aAliasList, *aliasString, aResultantString);
+
+ // ensure that the aliasString processing doesn't end in an infinite loop.
+ // In case it does , leave with KErrAuthServInvalidAliasStringExpression.
+ // For instance : fast = (medium & weak), medium = fast i.e
+ // medium = (medium & weak).
+
+ if(aResultantString.FindC(aAliasName) != KErrNotFound)
+ {
+ User::Leave(KErrAuthServInvalidAliasStringExpression);
+ }
+
+ TBool found = CheckForAliasInAliasString(aAliasList, aResultantString);
+ // 'resultantAliasString' may inturn contain an alias.So loop through the ProcessAliasStringL,
+ // until we end up with an alias string containing only plugin Id,plugin Type or a combination of both.
+ while(found)
+ {
+ for(TInt j = 0; j < aAliasList.Count(); ++j)
+ {
+ if(aResultantString.FindC(*aAliasList[j]) != KErrNotFound)
+ {
+ if(aResultantString.Length() > aliasStringPtr.MaxLength())
+ {
+ aliasString->ReAllocL(aResultantString.Length());
+ }
+
+ aliasStringPtr.Copy(aResultantString);
+ aResultantString.Close();
+
+ CAuthExpressionImpl::InsertSpaceBetweenOperatorsL(*aliasString, aResultantString);
+ if(aResultantString.Length() > aliasStringPtr.MaxLength())
+ {
+ aliasString->ReAllocL(aResultantString.Length());
+ }
+
+ aliasStringPtr.Copy(aResultantString);
+ aResultantString.Close();
+
+ ProcessAliasStringL(aAliasList, *aliasString, aResultantString);
+ // ensure that the aliasString processing doesn't end in an infinite loop.
+ // In case it does , leave with KErrArgument.
+ // For instance : fast = (medium & weak), medium = fast i.e
+ // medium = (medium & weak).
+ if(aResultantString.FindC(aAliasName) != KErrNotFound)
+ {
+ User::Leave(KErrAuthServInvalidAliasStringExpression);
+ }
+ break;
+ }
+ }
+
+ // check if 'resultantExpr' still contains an alias.
+ found = CheckForAliasInAliasString(aAliasList, aResultantString);
+
+ }
+
+ break;
+ }
+
+ CleanupStack::PopAndDestroy(aliasString);
+
+ //if the client supplied alias is not in the alias list, leave.
+ if(!aliasFound)
+ {
+ User::Leave(KErrUnknownAuthStrengthAlias);
+ }
+
+ }
+
+// Resets the training data for the supplied identity.
+//
+// @param aMessage Client message which contains the details of
+// identity and plugins for doing the reset
+void CAuthServer::ResetIdentityL(TInt aFunction, const RMessage2& aMessage)
+ {
+ // Check if either an authentication or a training is going on
+ if (ServerBusy())
+ {
+ aMessage.Complete(KErrServerBusy);
+ return;
+ }
+
+ // For reset by type only EAuthKnowledge type is supported
+ if (aFunction == EResetIdentityByType)
+ {
+ TAuthPluginType pluginType = static_cast<TAuthPluginType>(aMessage.Int1());
+ if (pluginType != EAuthKnowledge)
+ {
+ aMessage.Complete(KErrAuthServResetMayLoseIdentity);
+ return;
+ }
+ }
+
+ // Get the list of trained plugins for this identity
+ TIdentityId identityId = static_cast<TIdentityId>(aMessage.Int0());
+ RArray<TPluginId> trainedPluginIdList;
+ CleanupClosePushL(trainedPluginIdList);
+ iAuthDb2->TrainedPluginsListL(identityId, trainedPluginIdList);
+
+ // Ensure at least one plugin knows identity
+ TInt numTrained = trainedPluginIdList.Count();
+ if (numTrained < 1)
+ {
+ CleanupStack::PopAndDestroy(&trainedPluginIdList);
+ aMessage.Complete(KErrAuthServIdentityNotFound);
+ return;
+ }
+
+ // Try and ensure that after reset at least one plugin has an identity trained
+ // Since all the trained plugins for the identity are being reset make sure
+ // at least one of them is of the knowledge type to be reasonably sure it registers
+ // the new identity data
+ TBool knowledgePluginFound = EFalse;
+ for (TInt index = 0; index < numTrained; ++index)
+ {
+ TPluginId pluginId = trainedPluginIdList[index];
+ CAuthPluginInterface* plugin = iPluginMgr->PluginL(pluginId);
+ if (plugin->Type() == EAuthKnowledge)
+ {
+ knowledgePluginFound = ETrue;
+ break;
+ }
+ }
+ if (!knowledgePluginFound)
+ {
+ CleanupStack::PopAndDestroy(&trainedPluginIdList);
+ aMessage.Complete(KErrAuthServResetMayLoseIdentity);
+ return;
+ }
+
+ // Get the registration data
+ HBufC* regData = NULL;
+ TInt ipcArg = (aFunction == EResetIdentity) ? EIpcArgument1:EIpcArgument2;
+ regData = HBufC::NewLC(aMessage.GetDesLengthL(ipcArg));
+ TPtr regPtr = regData->Des();
+ aMessage.ReadL(ipcArg, regPtr);
+
+ // Finally start the reset process
+ // Generate a new protection key
+ CProtectionKey* protKey = CProtectionKey::NewLC(iKeySize);
+ TInt lastErr = KErrNone;
+ TBool oneSuccess = EFalse; // To keep track if at least one reset succeeded
+ for (TInt index = 0; index < numTrained; ++index)
+ {
+ TPluginId pluginId = trainedPluginIdList[index];
+ CAuthPluginInterface* plugin = iPluginMgr->PluginL(pluginId);
+ HBufC8* result = NULL;
+ TInt err = KErrNone;
+ // For reset by type the registration data needs to be specified only for the plugins of specified type
+ // and this restricted to knowledge type only
+ if ((aFunction == EResetIdentity) ||
+ ((aFunction == EResetIdentityByType) && (plugin->Type() == EAuthKnowledge)))
+ {
+ err = plugin->Reset(identityId, *regData, result);
+ }
+ else
+ {
+ err = plugin->Reset(identityId, KNullDesC, result);
+ }
+ if (err == KErrNone && result)
+ {
+ oneSuccess = ETrue;
+ // Use the plugin data to generate transient key and then encrypt the protection key
+ // using the transient key. A plugin may not return data if it does not use the supplied
+ // registration information
+ CleanupStack::PushL(result);
+ CTransientKeyInfo* keyInfo = CreateKeyInfoLC(pluginId, *result, *protKey);
+ // Replace the trained information in the db
+ iAuthDb2->SetTrainedPluginL(identityId, pluginId, *keyInfo);
+ CleanupStack::PopAndDestroy(2, result); // keyInfo
+ }
+ else if (err == KErrNone)
+ {
+ oneSuccess = ETrue;
+ // Remove the entry in the auth db for the plugin
+ // Ignore errors
+ TRAP_IGNORE(iAuthDb2->RemoveTrainedPluginL(identityId, pluginId));
+ }
+ else
+ {
+ // Remember the last error
+ lastErr = err;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(3, &trainedPluginIdList); // regData, protKey
+
+ // If none of the plugins reset correctly then return the last error
+ if (oneSuccess)
+ {
+ lastErr = KErrNone;
+ }
+
+ aMessage.Complete(lastErr);
+ }
+
+// Resets the training data for the supplied identity.
+//
+// @param aMessage Client message which contains the details of
+// identity and plugins for doing the reset
+void CAuthServer::ResetIdentityByListL(const RMessage2& aMessage)
+ {
+ // Check if either an authentication or a training is going on
+ if (ServerBusy())
+ {
+ aMessage.Complete(KErrServerBusy);
+ return;
+ }
+
+ // Get the list of trained plugins for this identity
+ TIdentityId identityId = static_cast<TIdentityId>(aMessage.Int0());
+ RArray<TPluginId> trainedPluginIdList;
+ CleanupClosePushL(trainedPluginIdList);
+ iAuthDb2->TrainedPluginsListL(identityId, trainedPluginIdList);
+
+ // Ensure at least one plugin knows identity
+ TInt numTrained = trainedPluginIdList.Count();
+ if (numTrained < 1)
+ {
+ CleanupStack::PopAndDestroy(&trainedPluginIdList);
+ aMessage.Complete(KErrAuthServIdentityNotFound);
+ return;
+ }
+
+ // Extract the array of plugin ids and their registration information
+ RArray<TPluginId> pluginIdList;
+ CleanupClosePushL(pluginIdList);
+ HBufC8* buf = HBufC8::NewLC(aMessage.GetDesLengthL(EIpcArgument1));
+ TPtr8 ptr = buf->Des();
+ aMessage.ReadL(EIpcArgument1, ptr);
+ RDesReadStream stream(*buf);
+ CleanupClosePushL(stream);
+ InternalizeArrayL(pluginIdList, stream);
+ CleanupStack::PopAndDestroy(2, buf); // stream
+
+ RPointerArray<HBufC> regInfoList;
+ CleanupResetAndDestroyPushL(regInfoList);
+ buf = HBufC8::NewLC(aMessage.GetDesLengthL(EIpcArgument2));
+ ptr.Set(buf->Des());
+ aMessage.ReadL(EIpcArgument2, ptr);
+ stream.Open(*buf);
+ CleanupClosePushL(stream);
+ InternalizePointerArrayL(regInfoList, stream);
+ CleanupStack::PopAndDestroy(2, buf); // stream
+
+ // Sanity check
+ if (pluginIdList.Count() != regInfoList.Count())
+ {
+ CleanupStack::PopAndDestroy(3, &trainedPluginIdList); // pluginIdList, regInfoList
+ aMessage.Complete(KErrArgument);
+ return;
+ }
+
+ // Prepare an array of TPluginResetDetails to aid during resetting
+ RPointerArray<TPluginResetDetails> resetDetails;
+ CleanupResetAndDestroyPushL(resetDetails);
+
+ for (TInt index = 0; index < numTrained; ++index)
+ {
+ TPluginId pluginId = trainedPluginIdList[index];
+ // Check if the trained plugin needs to be sent registration data
+ TInt indexA = pluginIdList.Find(pluginId);
+
+ TPluginResetDetails *resetDetailsEntry;
+ if (indexA != KErrNotFound)
+ {
+ // Note: Ownership of the descriptor pointers remains with regInfoList
+ resetDetailsEntry = new (ELeave) TPluginResetDetails(pluginId, *regInfoList[indexA]);
+ }
+ else
+ {
+ resetDetailsEntry = new (ELeave) TPluginResetDetails(pluginId, KNullDesC());
+ }
+ CleanupStack::PushL(resetDetailsEntry);
+ resetDetails.AppendL(resetDetailsEntry);
+ CleanupStack::Pop(resetDetailsEntry);
+ }
+
+ // Try and ensure that after reset at least one plugin has an identity trained
+ // Since all the trained plugins for the identity are being reset make sure
+ // at least one of them is of the knowledge type and is being passed the registration data
+ // to be reasonably sure it registers the new identity data
+ TBool knowledgePluginFound = EFalse;
+ for (TInt index = 0; index < numTrained; ++index)
+ {
+ TPluginId pluginId = resetDetails[index]->PluginId();
+ CAuthPluginInterface* plugin = iPluginMgr->PluginL(pluginId);
+ if ((plugin->Type() == EAuthKnowledge) && (resetDetails[index]->RegistrationData() != KNullDesC))
+ {
+ knowledgePluginFound = ETrue;
+ break;
+ }
+ }
+ if (!knowledgePluginFound)
+ {
+ CleanupStack::PopAndDestroy(4, &trainedPluginIdList); // pluginIdList, regInfoList, resetDetails
+ aMessage.Complete(KErrAuthServResetMayLoseIdentity);
+ return;
+ }
+
+ // Finally start the reset process
+ // Generate a new protection key
+ CProtectionKey* protKey = CProtectionKey::NewLC(iKeySize);
+ TInt lastErr = KErrNone;
+ TBool oneSuccess = EFalse; // To keep track if at least one reset succeeded
+ for (TInt index = 0; index < numTrained; ++index)
+ {
+ TPluginResetDetails* reset = resetDetails[index];
+ TPluginId pluginId = reset->PluginId();
+ CAuthPluginInterface* plugin = iPluginMgr->PluginL(pluginId);
+ HBufC8* result = NULL;
+ TInt err = plugin->Reset(identityId, reset->RegistrationData(), result);
+ if (err == KErrNone && result)
+ {
+ oneSuccess = ETrue;
+ // Use the plugin data to generate transient key and then encrypt the protection key
+ // using the transient key. A plugin may not return data if it does not use the supplied
+ // registration information
+ CleanupStack::PushL(result);
+ CTransientKeyInfo* keyInfo = CreateKeyInfoLC(pluginId, *result, *protKey);
+ // Replace the trained information in the db
+ iAuthDb2->SetTrainedPluginL(identityId, pluginId, *keyInfo);
+ CleanupStack::PopAndDestroy(2, result); // keyInfo
+ }
+ else if (err == KErrNone)
+ {
+ oneSuccess = ETrue;
+ // Remove the entry in the auth db for the plugin
+ // Ignore errors
+ TRAP_IGNORE(iAuthDb2->RemoveTrainedPluginL(identityId, pluginId));
+ }
+ else
+ {
+ // Remember the last error
+ lastErr = err;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(5, &trainedPluginIdList); // pluginIdList, regInfoList, resetDetails, protKey
+
+ // If none of the plugins reset correctly then return the last error
+ if (oneSuccess)
+ {
+ lastErr = KErrNone;
+ }
+
+ aMessage.Complete(lastErr);
+ }
+
+// Generates and returns transient key info using the supplied plugin data and the protection key
+CTransientKeyInfo* CAuthServer::CreateKeyInfoLC(TPluginId aPluginId, const TDesC8& aPluginData, const CProtectionKey& aProtKey)
+ {
+ CTransientKeyInfo* keyInfo = CTransientKeyInfo::NewLC(aPluginId);
+
+ CTransientKey* transKey = keyInfo->CreateTransientKeyL(aPluginData);
+ CleanupStack::PushL(transKey);
+
+ CEncryptedProtectionKey* encProtKey = transKey->EncryptL(aProtKey);
+ CleanupStack::PushL(encProtKey);
+
+ keyInfo->SetEncryptedProtectionKeyL(encProtKey);
+ CleanupStack::Pop(encProtKey);
+ CleanupStack::PopAndDestroy(transKey);
+ return keyInfo;
+ }
+
+/**
+ Checks if the value of strength alias inturn contains an alias.
+
+ @param aAuthAliasList an array of authentication strengths as obtained from
+ authserver cenrep file.
+ @param aAliasString an alias string containing the alias to be searched for.
+
+ */
+
+TBool CAuthServer::CheckForAliasInAliasString(RPointerArray<HBufC>& aAuthAliasList, const TDes& aAliasString)
+ {
+ // find a match for the client supplied alias from the aliasList.
+ for(TInt i = 0; i < aAuthAliasList.Count(); ++i)
+ {
+ TInt found = aAliasString.FindC(*aAuthAliasList[i]);
+ if(found > 0)
+ {
+ return ETrue;
+ }
+ }
+
+ return EFalse;
+ }
+
+/**
+ Processes an alias string, This method is called recursively until we end
+ up with an alias string containing only pluginIds and pluginTypes or a
+ combination of both.
+
+
+ @param aAliasList an array of authentication strengths as obtained from
+ authserver cenrep file.
+ @param aAliasStringToBeProcessed an alias string to be processed.
+ @param aResultantAliasString Buffer to be populated with an alias string resulting from processing aAliasStringToBeProcessed.
+
+ */
+
+void CAuthServer::ProcessAliasStringL(RPointerArray<HBufC>& aAliasList, const TDesC& aAliasStringToBeProcessed, RBuf& aResultantAliasString)
+ {
+ TBuf<KDefaultBufferSize> exprString;
+ HBufC* aliasString = HBufC::NewLC(KMaxBufferSize);
+ TPtr aliasStringPtr(aliasString->Des());
+
+ TLex input(aAliasStringToBeProcessed);
+ _LIT(KDelimiter, " ");
+ TBool aliasFoundInString = EFalse;
+
+ //iterate through the obtained expression to verify if it contains any strength subsets.
+ for(TPtrC token = input.NextToken(); token.Size() > 0; token.Set(input.NextToken()))
+ {
+ TInt resultingLen = 0;
+ aliasFoundInString = EFalse;
+ for(TInt i = 0; i < aAliasList.Count(); ++i)
+ {
+ if(token.FindC(*aAliasList[i]) != KErrNotFound)
+ {
+ aliasFoundInString = ETrue;
+ iAuthRepository->GetAliasDefinitionL(i, exprString);
+ if(exprString.Length() == 0)
+ {
+ User::Leave(KErrAuthStrengthAliasNotDefined);
+ }
+
+ // resulting length obtained by appending exprString ,KCloseBracket and KOpenBracket to aliasString.
+ resultingLen = (exprString.Length() + 2);
+ if(resultingLen > KMaxBufferSize)
+ {
+ aliasString->ReAllocL(resultingLen);
+ }
+
+ aliasStringPtr.Append(KOpenBracket);
+ aliasStringPtr.Append(exprString);
+ aliasStringPtr.Append(KCloseBracket);
+ break;
+ }
+ }
+
+ //if the token is an operator or a plugin type or pluginId, append it to aResultantExpr.
+ if(!aliasFoundInString)
+ {
+ // resulting length obtained by appending token and delimiter to be aliasString.
+ resultingLen = (exprString.Length() + token.Length() + 1);
+ if(resultingLen > KMaxBufferSize)
+ {
+ aliasString->ReAllocL(resultingLen);
+ }
+
+ aliasStringPtr.Append(token);
+ aliasStringPtr.Append(KDelimiter);
+ }
+ }
+
+ CleanupStack::Pop(aliasString);
+ aResultantAliasString.Assign(aliasString);
+
+ }
+
+
+/**
+ *
+ * @param aMessage the message to process
+ **/
+void CAuthServer::RegisterIdentityL(const RMessage2& aMessage)
+ {
+ if (ServerBusy())
+ {
+ aMessage.Complete(KErrServerBusy);
+ return;
+ }
+
+ TIdentityId id = 0;
+ TPckg<TIdentityId> idPkg(id);
+ TRandom::RandomL(idPkg);
+
+ CProtectionKey* key = CProtectionKey::NewL(iKeySize);
+
+ iTrainingMgr->RegisterIdentityL(aMessage, id, *key);
+ }
+
+/**
+ *
+ * @param aMessage the message to process
+ **/
+void CAuthServer::CancelL(const RMessage2& aMessage)
+ {
+ TInt err = KErrNone;
+
+ if (iTrainingMgr->IsBusy())
+ {
+ iTrainingMgr->Cancel();
+ }
+ else if (iAuthTransaction != 0)
+ {
+ if (aMessage.SecureId() == iAuthTransaction->Message().SecureId())
+ {
+ iEvaluator->Cancel();
+ }
+ else
+ {
+ // Shouldn't come here since we don't support share-able sessions
+ err = KErrInUse;
+ }
+ }
+ aMessage.Complete(err);
+ }
+
+
+/**
+ Remove the supplied identity from the database.
+
+ @param aMessage Client which contains identity
+ to remove.
+ */
+void CAuthServer::RemoveIdentityL(const RMessage2& aMessage)
+ {
+ TInt result = KErrNone;
+
+ //The identity to be removed
+ TIdentityId id = static_cast<TIdentityId>(aMessage.Int0());
+
+ //Check if the identity to be removed is not the default identity.
+ TIdentityId defaultIdentity = iAuthDb2->DefaultIdentityL();
+
+ if(defaultIdentity != id)
+ {
+ iAuthDb2->RemoveIdentityL(id);
+
+ if (iLastIdentity && iLastIdentity->Id() == id)
+ {
+ delete iLastIdentity;
+ iLastIdentity = 0;
+ iLastAuthTime = 0L;
+ }
+ iPluginMgr->ForgetIdentityL(id);
+ }
+ else
+ {
+ result = KErrAuthServCanNotRemoveDefaultIdentity;
+ }
+ aMessage.Complete(result);
+ }
+
+/**
+ * @return true if either the training mgr or authentication transaction
+ * is busy
+ **/
+TBool CAuthServer::ServerBusy()
+ {
+ return iTrainingMgr->IsBusy() || iAuthTransaction != 0;
+ }
+
+
+/**
+ *
+ * @param aMessage the message to process
+ **/
+void CAuthServer::TrainPluginL(const RMessage2& aMessage)
+ {
+ if (ServerBusy())
+ {
+ aMessage.Complete(KErrServerBusy);
+ return;
+ }
+
+ if (iLastIdentity == 0 || iLastIdentity->Id() != aMessage.Int0())
+ {
+ // we need a cached identity to get the protection key
+ aMessage.Complete(KErrAuthServAuthenticationRequired);
+ return;
+ }
+
+ TIdentityId retrainId = aMessage.Int0();
+
+ //The default identity cannot be retrained.
+ TIdentityId defaultIdentity = iAuthDb2->DefaultIdentityL();
+
+ if(defaultIdentity == retrainId)
+ {
+ aMessage.Complete(KErrNotSupported);
+ return;
+ }
+
+ HBufC8* data = HBufC8::NewLC(iLastIdentity->Key().KeyData().Size());
+ *data = iLastIdentity->Key().KeyData();
+
+ CProtectionKey* key = CProtectionKey::NewL(data);
+ CleanupStack::Pop(data);
+
+ iTrainingMgr->TrainPluginL(aMessage, *key);
+
+ }
+
+
+
+/**
+ * Remove the supplied identity, plugin pair from the
+ * authentication database.
+ *
+ * @param aMessage Client message which contains the
+ * identity and the plugin.
+ **/
+void CAuthServer::ForgetPluginL(const RMessage2& aMessage)
+ {
+ if (ServerBusy())
+ {
+ aMessage.Complete(KErrServerBusy);
+ return;
+ }
+
+ TIdentityId id = static_cast<TIdentityId>(aMessage.Int0());
+ TPluginId plugin = static_cast<TPluginId>(aMessage.Int1());
+ TInt err = KErrNone;
+
+ TInt numTrained = iAuthDb2->NumTrainedPluginsL(id);
+
+ switch (numTrained)
+ {
+ case 0:
+ err = KErrAuthServNoSuchIdentity;
+ break;
+ case 1:
+ err = KErrAuthServCanNotRemoveLastPlugin;
+ break;
+ default:
+ iAuthDb2->RemoveTrainedPluginL(id, plugin);
+ iPluginMgr->PluginL(plugin)->Forget(id);
+ break;
+ }
+
+ aMessage.Complete(err);
+ }
+
+
+void CAuthServer::EvaluateL(TPluginId aPluginId,
+ TIdentityId& aIdentityId,
+ CAuthExpressionImpl::TType aType,
+ TRequestStatus& aStatus)
+ {
+
+ if(aPluginId == 0 && aType == CAuthExpressionImpl::ENull)
+ {
+ aPluginId = iAuthRepository->DefaultPluginL();
+ }
+
+ CAuthPluginInterface* plugin = iPluginMgr->PluginL(aPluginId);
+
+ if (plugin != 0)
+ {
+ const HBufC* clientMessage = iAuthTransaction->ClientMessage();
+
+ HBufC8*& data = iAuthTransaction->AddPluginL(aPluginId, aIdentityId);
+
+ if (plugin->IsActive())
+ {
+ plugin->Identify(aIdentityId, *clientMessage, data, aStatus);
+ }
+
+ else
+ {
+ User::Leave(KErrAuthServPluginNotActive);
+ }
+ }
+ }
+/**
+ * @see MEvaluatorPluginInterface::Evaluate
+ **/
+void CAuthServer::Evaluate(TPluginId aPluginId,
+ TIdentityId& aIdentityId,
+ CAuthExpressionImpl::TType aType,
+ TRequestStatus& aStatus)
+ {
+ TRAPD(err, EvaluateL(aPluginId, aIdentityId, aType, aStatus));
+
+ if (err != KErrNone)
+ {
+ TRequestStatus* status = &aStatus;
+ User::RequestComplete(status, err);
+ }
+ }
+
+/**
+ * Retrieve the preferred plugin for the supplied type and
+ * get an identity from it.
+ * @see MEvaluatorPluginInterface::Evaluate
+ *
+ **/
+void CAuthServer::Evaluate(TAuthPluginType aPluginType,
+ TIdentityId& aIdentityId,
+ CAuthExpressionImpl::TType aType,
+ TRequestStatus& aStatus)
+ {
+ TPluginId id = 0;
+ TRAPD(r, id = iAuthDb2->PreferredPluginL(aPluginType));
+ if (r == KErrNone)
+ {
+ Evaluate(id, aIdentityId, aType, aStatus);
+ }
+ else
+ {
+ // Pass back error (can happen if a user preference hasn't been defined)
+ aStatus = KRequestPending;
+ TRequestStatus* rs = &aStatus;
+ User::RequestComplete(rs, r);
+ }
+ }
+
+/**
+ * Completes the message and sends the id on it's way back to the client
+ **/
+void CAuthServer::CompleteAuthenticationL(const RMessagePtr2& aMessage,
+ CIdentity* aId)
+ {
+ // write to client
+ HBufC8* idBuff = HBufC8::NewLC(KDefaultBufferSize);
+ TPtr8 idPtr = idBuff->Des();
+ RDesWriteStream writeStream(idPtr);
+ writeStream << *aId;
+ writeStream.CommitL();
+
+ TInt clientBuffSize = aMessage.GetDesMaxLength(2);
+
+ if (clientBuffSize >= idBuff->Size())
+ {
+ aMessage.Write(2, *idBuff);
+ }
+ else
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ CleanupStack::PopAndDestroy(idBuff);
+
+ aMessage.Complete(KErrNone);
+ }
+
+/**
+ * @see MEvaluatorClientInterface::EvaluationSucceeded
+ **/
+void CAuthServer::EvaluationSucceeded(TIdentityId aIdentityId)
+ {
+
+ TRAPD(err, EvaluationSucceededL(aIdentityId));
+
+ switch(err)
+ {
+ case KErrNone:
+ break;
+ default:
+ EvaluationFailed(err);
+ }
+ }
+
+
+/**
+ * The full, leaving, implementation of EvaluationSucceeded (which is a trap
+ * harness).
+ *
+ * @param aIdentityId the identity discovered
+ **/
+void CAuthServer::EvaluationSucceededL(TIdentityId aIdentityId)
+ {
+
+ CAuthTransaction::RResultArray& results = iAuthTransaction->Results();
+
+ HBufC8* data = 0;
+ TPluginId plugin = KUnknownPluginId;
+
+ TLastAuth lastAuth;
+ lastAuth.iId = aIdentityId;
+
+ for (TInt i = 0 ; i < results.Count() ; ++i)
+ {
+ if (aIdentityId == *results[i]->iId)
+ {
+ plugin = results[i]->iPlugin;
+ data = results[i]->iData;
+ UpdateAuthL(lastAuth, plugin);
+ }
+ }
+
+ CProtectionKey* key = 0;
+
+ // Ensure that the ID and DATA are valid.
+ if (( aIdentityId != KUnknownIdentity ) && ( data != 0 ))
+ {
+ // get the protection key
+ CTransientKeyInfo* keyInfo = iAuthDb2->KeyInfoL(aIdentityId, plugin);
+ CleanupStack::PushL(keyInfo);
+
+ CTransientKey* transKey = keyInfo->CreateTransientKeyL(*data);
+ CleanupStack::PushL(transKey);
+
+ key = transKey->DecryptL(keyInfo->EncryptedKey());
+ CleanupStack::PopAndDestroy(2,keyInfo);
+ CleanupStack::PushL(key);
+
+ // convert to a client key if we need to
+ if (iAuthTransaction->ClientKey())
+ {
+ CProtectionKey* key2 = key->ClientKeyL(iAuthTransaction->ClientSid());
+
+ CleanupStack::PopAndDestroy(key);
+ key = key2;
+ CleanupStack::PushL(key);
+ }
+ }
+ else
+ {
+ // create a blank key
+ key = CProtectionKey::NewLC(0);
+
+ // clear the cached identity
+ delete iLastIdentity;
+ iLastIdentity = 0;
+ iLastAuthTime = 0L;
+ }
+
+ HBufC* str =
+ StringOrNullLC(iAuthTransaction->WithString(), aIdentityId);
+
+ // create the client identity object
+ CIdentity* identity = CIdentity::NewL(aIdentityId, key, str);
+ CleanupStack::Pop(2, key);
+ CleanupStack::PushL(identity);
+
+ CompleteAuthenticationL(iAuthTransaction->Message(),
+ identity);
+
+ if (aIdentityId != KUnknownIdentity)
+ {
+ TIdentityId oldId = iLastIdentity ? iLastIdentity->Id() : 0;
+
+ // cache the latest id
+ delete iLastIdentity;
+ iLastIdentity = identity;
+ if(iLastAuthTime.UniversalTimeSecure() == KErrNoSecureTime)
+ {
+ // Fall back to nonsecure time.
+ iLastAuthTime.UniversalTime();
+ }
+ // and publish it
+ lastAuth.iAuthTime = iLastAuthTime;
+ TPckg<TLastAuth> authPckg(lastAuth);
+ User::LeaveIfError(iAuthProperty.Set(authPckg));
+
+ // if the identity has changed publish that fact
+ if (oldId != aIdentityId)
+ {
+ User::LeaveIfError(iAuthEventProperty.Set(aIdentityId));
+ }
+
+ CleanupStack::Pop(identity);
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy(identity);
+ }
+ delete iAuthTransaction;
+ iAuthTransaction = 0;
+ }
+
+/**
+ * Tells the authserver to cancel the current evaluation (i.e. call to
+ * the plugin)
+ *
+ * @see MEvaluatorPluginInterface::Evaluate
+ *
+ **/
+void CAuthServer::CancelEvaluate()
+ {
+ if (iAuthTransaction)
+ {
+ TPluginId pluginId = iAuthTransaction->LastPluginId();
+ CAuthPluginInterface* plugin = 0;
+ TRAPD(err, (plugin = iPluginMgr->PluginL(pluginId)));
+ if (err == KErrNone)
+ {
+ plugin->Cancel();
+ }
+ }
+ }
+
+
+/**
+ * @see MEvaluatorClientInterface::EvaluationFailed
+ **/
+void CAuthServer::EvaluationFailed(TInt aReason)
+ {
+ iAuthTransaction->Message().Complete(aReason);
+ delete iAuthTransaction;
+ iAuthTransaction = 0;
+ // there's nothing we can do here. Panic?
+ TRAP_IGNORE(ClearPropertiesL());
+ }
+
+
+void CAuthServer::UpdateAuthL(TLastAuth& aAuth, TPluginId aPlugin)
+ {
+ CAuthPluginInterface* plugin = iPluginMgr->PluginL(aPlugin);
+
+ aAuth.iMaxCombinations =
+ Max(aAuth.iMaxCombinations, plugin->MinEntropy());
+ aAuth.iFalsePositiveRate =
+ Max(aAuth.iFalsePositiveRate, plugin->FalsePositiveRate());
+ aAuth.iFalseNegativeRate =
+ Max(aAuth.iFalseNegativeRate, plugin->FalseNegativeRate());
+ ++aAuth.iNumFactors;
+ }
+
+
+/**
+ * Free all the uncompressable memory before the
+ * heap mark is set/reset to get the OOM tests to pass.
+ **/
+void CAuthServer::FreeMemoryBeforeHeapMark()
+ {
+#ifdef _DEBUG
+
+ if(iTrainingMgr)
+ {
+ delete iTrainingMgr;
+ iTrainingMgr = 0;
+ }
+
+ if(iPluginMgr)
+ {
+ delete iPluginMgr;
+ iPluginMgr = 0;
+ }
+
+ if(iLastIdentity)
+ {
+ delete iLastIdentity;
+ iLastIdentity = 0;
+ }
+
+ iAuthDb2->CloseDbFile();
+
+ REComSession::FinalClose();
+
+#endif
+ }
+
+
+/**
+ * Recreate all the variables deleted after the heap mark has
+ * been set/reset.
+ **/
+void CAuthServer::SetupVariablesAfterHeapMarkEndL()
+ {
+#ifdef _DEBUG
+
+ //Opening Db file.
+ TFileName dbName(KDbName);
+ dbName[0] = RFs::GetSystemDriveChar();
+ iAuthDb2->OpenDbFileL(iFs, dbName);
+
+ //Creating plugin manager.
+ if(!iPluginMgr)
+ {
+ iPluginMgr = CPluginMgr::NewL();
+ }
+
+ //Creating training manager.
+ if(!iTrainingMgr)
+ {
+ iTrainingMgr = new (ELeave) CTrainingMgr(*iPluginMgr, *iAuthDb2, *iAuthRepository);
+ }
+#endif
+ }
+
+/**
+ * Things to be done before the heap mark is set/reset
+ * during OOM testing
+ **/
+void CAuthServer::DoPreHeapMarkOrCheckL()
+ {
+#ifdef _DEBUG
+ FreeMemoryBeforeHeapMark();
+#endif
+ }
+
+/**
+ * Things to be done after the heap mark is set/reset
+ * during OOM testing
+ **/
+void CAuthServer::DoPostHeapMarkOrCheckL()
+ {
+#ifdef _DEBUG
+ SetupVariablesAfterHeapMarkEndL();
+#endif
+ }
+