installationservices/swcomponentregistry/source/server/scrserver.cpp
branchRCL_3
changeset 25 7333d7932ef7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swcomponentregistry/source/server/scrserver.cpp	Tue Aug 31 15:21:33 2010 +0300
@@ -0,0 +1,467 @@
+/*
+* Copyright (c) 2008-2010 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: 
+* Implements CScrServer providing management of SCR services.
+*
+*/
+
+
+/**
+ @file
+ @internalComponent
+ @released
+*/
+
+#include "scrserver.h"
+#include "scrrequestimpl.h"
+#include "usiflog.h"
+#include <scs/cleanuputils.h>
+#include "scrhelperclient.h"
+#include <scs/securityutils.h>
+
+using namespace Usif;
+
+static const TUint scrRangeCount = 13;
+
+static const TInt scrRanges[scrRangeCount] =
+	{
+	0,							 // Range-0 - 0 to EBaseSession-1. Not used.
+	CScsServer::EBaseSession,	 // Range-1 - EBaseSession to EBaseMustAllow exclusive.
+	CScsServer::EBaseSession | EGetSingleComponentSize, // Modification and transaction APIs have custom checks
+	CScsServer::EBaseSession | EGetComponentIdListSize, // Component-specific APIs are free for all
+	CScsServer::EBaseSession | EGetApplicationLaunchersSize, // Getting all component IDs is restricted to ReadUserData
+	CScsServer::EBaseSession | EGetIsMediaPresent, // Only allowed by apparc
+	CScsServer::EBaseSession | EAddApplicationEntry, // Component-specific APIs are free for all
+	CScsServer::EBaseSession | EGetPluginUidWithMimeType, // Custom checks (as with the rest of modification APIs)
+	CScsServer::EBaseSession | EAddSoftwareType, // File filter sub-sessions and plugin-fetching APIs are free for all	
+	CScsServer::EBaseSubSession | EOpenComponentsView, // Software Type management APIs are only allowed for SWI 
+	CScsServer::EBaseSubSession | EOpenFileList, // Component filter sub-sessions require ReadUserData	
+	CScsServer::EBaseSubSession | EOpenApplicationRegistrationInfoView, // Always pass
+	CScsServer::EBaseMustAllow // Application Registration view to be only allowed by apparc, the rest of the range is reserved for SCS, and must be allowed( EBaseMustAllow to KMaxTInt inclusive)	
+	};
+
+static const TUint8 scrElementsIndex[scrRangeCount] =
+	{
+	CPolicyServer::ENotSupported, // Range 0 is not supported.
+	CPolicyServer::ECustomCheck,
+	CPolicyServer::EAlwaysPass,
+	0, // Require ReadUserData
+	2, // Only Apparc process can invoke	
+	CPolicyServer::EAlwaysPass,
+	CPolicyServer::ECustomCheck,
+	CPolicyServer::EAlwaysPass,	
+	1, // Only SWI process can invoke	
+	0, // Require ReadUserData
+	CPolicyServer::EAlwaysPass,
+	2, // Only Apparc process can invoke
+	CPolicyServer::EAlwaysPass 
+	};							
+
+static const CPolicyServer::TPolicyElement scrElements[] =
+	{
+	{_INIT_SECURITY_POLICY_C1(ECapabilityReadUserData), CPolicyServer::EFailClient},
+	{_INIT_SECURITY_POLICY_S0(KSisRegistryServerSid.iId), CPolicyServer::EFailClient},
+	{_INIT_SECURITY_POLICY_S0(KApparcServerSid.iId), CPolicyServer::EFailClient}	
+	};
+
+static const CPolicyServer::TPolicy scrPolicy =
+	{
+	CPolicyServer::EAlwaysPass, // Allow all connections
+	scrRangeCount,
+	scrRanges,
+	scrElementsIndex,
+	scrElements,
+	};
+
+//
+// CScrServer
+//
+
+CScrServer::CScrServer()
+/**
+	Intializes the SCR server object with its version and policy.
+ */
+	:	CScsServer(ScrServerVersion(), scrPolicy)
+		{
+		DEBUG_PRINTF(_L8("SCR server construction!"));
+		}
+
+CScrServer::~CScrServer()
+/**
+	Destructor. Cleanup the SCR Server.
+ */
+	{
+	DEBUG_PRINTF(_L8("SCR server destruction!"));
+	delete iRequestImpl;
+	iDatabaseFile.Close();
+	iJournalFile.Close();
+	iFs.Close();
+	iSubsessionOwners.Close();
+	}
+	
+	
+CScrServer* CScrServer::NewLC()
+/**
+	Factory function allocates a new instance of CScrServer.
+
+	@return		The newly created instance of CScrServer which is left on the cleanup stack.
+ */
+	{
+	CScrServer *self = new (ELeave) CScrServer();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+
+void CScrServer::ConstructL()
+/**
+	Second phase constructor starts the SCR server.
+ */
+	{
+	// StartL() must be called first in order to avoid concurrency issue when starting the server from two or more processes
+	StartL(KSoftwareComponentRegistryName);
+	CScsServer::ConstructL(KScrServerShutdownPeriod);
+	SetupL();
+	}
+
+void CheckFilePathL(RFs& aFs, RFile& aFile, const TDesC& aExpectedPath)
+	{
+	RBuf fileName;
+	fileName.CreateL(KMaxFileName);
+	fileName.CleanupClosePushL();
+	User::LeaveIfError(aFile.FullName(fileName));
+	
+	RBuf expectedFileName;
+	expectedFileName.CreateL(aExpectedPath.Length());
+	expectedFileName.CleanupClosePushL();
+	expectedFileName.Copy(aExpectedPath);
+	expectedFileName[0] = aFs.GetSystemDriveChar();
+	
+	__ASSERT_ALWAYS(!fileName.CompareF(expectedFileName), User::Leave(KErrBadHandle));
+		
+	CleanupStack::PopAndDestroy(2, &fileName); // fileName, expectedFileName
+	}
+
+void CScrServer::SetupL()
+	{
+	// Connect to the file server
+	User::LeaveIfError(iFs.Connect());
+	User::LeaveIfError(iFs.ShareProtected());
+	
+	// Connect to the SCR database
+	RScrHelper sh;
+	User::LeaveIfError(sh.Connect());
+	CleanupClosePushL(sh);
+	
+	// Retrieve handles for database and journal files
+	sh.RetrieveFileHandlesL(iDatabaseFile, iJournalFile);
+	CleanupStack::PopAndDestroy(&sh);
+	
+	// Check if the retrieved file handles belong to the expected files (KScrDatabaseFilePath/KScrJournalFilePath).
+	// This is an extra security measure in the SCR to check that the file handle transferred from SCR Helper Server  
+	// really corresponds to scr.db/scr.db-journal in the expected location.
+	CheckFilePathL(iFs, iDatabaseFile, KScrDatabaseFilePath);
+	CheckFilePathL(iFs, iJournalFile, KScrJournalFilePath);
+	
+	ReconnectL();
+	}
+
+CScsSession* CScrServer::DoNewSessionL(const RMessage2& aMessage)
+/**
+	Implement CScsServer by allocating a new instance of CScrSession.
+
+	@param	aMessage	Standard server-side handle to message.
+	@return				New instance of the SCR session class which is owned by the caller.
+ */
+	{
+	DEBUG_PRINTF(_L8("SCR session creation!"));
+	return CScrSession::NewL(*this, aMessage);
+	}
+
+CPolicyServer::TCustomResult CScrServer::CheckComponentIdMatchingEnvironmentL(const RMessage2& aMsg, TBool aCheckForSingleApp)
+	{	
+	TComponentId componentId = 0;
+	if(aCheckForSingleApp)
+	    {
+        // Get the application uid from RMessage2
+        TInt applicationUid = aMsg.Int0();        
+        // Get the component id for the application            
+        if(!iRequestImpl->GetComponentIdForAppInternalL(TUid::Uid(applicationUid), componentId))
+            return EFail;
+	    }
+	else
+	    {
+	    componentId = CScrRequestImpl::GetComponentIdFromMsgL(aMsg);
+	    }
+	
+	TSecureId clientSid = aMsg.SecureId();
+
+    if (componentId == 0)
+        {
+        if (clientSid == KSisRegistryServerSid)
+            return EPass;
+        }   
+    
+    TBool vaildSid = EFalse;
+	RArray<TSecureId> installerSids;
+	CleanupClosePushL(installerSids);
+	if (iRequestImpl->GetInstallerOrExecutionEnvSidsForComponentL(componentId, installerSids))
+	    {
+        TInt count = installerSids.Count();
+        for (TInt i = 0; i < count; i++)
+            {
+            if (clientSid == installerSids[i])
+                {
+                vaildSid = ETrue;
+                break;
+                }
+            }
+	    }
+	CleanupStack::PopAndDestroy(&installerSids);
+	
+	if (vaildSid)
+		return EPass;
+			
+	DEBUG_PRINTF3(_L("Neither installer nor execution environment matched the client while checking for component-matching environment. Client SID %d, Component ID %d"), 
+			TUint32(clientSid), componentId);
+	return EFail;
+	}
+	
+CPolicyServer::TCustomResult CScrServer::CheckDeleteComponentAllowedL(const RMessage2& aMsg)	
+	{
+	const TUint KSifServerSid = 0x10285BCB;	
+	
+	if (CheckComponentIdMatchingEnvironmentL(aMsg) == EPass)
+		return EPass;
+		
+	TSecureId clientSid = aMsg.SecureId();		
+	TComponentId componentId = CScrRequestImpl::GetComponentIdFromMsgL(aMsg);
+	// If a component does not have corresponding environments, it means that it is orphaned. In this case, SIF is allowed to forcefully remove it
+	if (iRequestImpl->GetIsComponentOrphanedL(componentId) && (TUint32(clientSid) == KSifServerSid))
+		{
+		DEBUG_PRINTF2(_L("Allowing SIF to uninstall orphaned component %d"), componentId);
+		return EPass;	
+		}
+		
+	return EFail;
+	}
+
+CPolicyServer::TCustomResult CScrServer::CheckSoftwareNameMatchingEnvironmentL(const RMessage2& aMsg)
+	{
+	HBufC* softwareTypeName = CScrRequestImpl::GetSoftwareTypeNameFromMsgLC(aMsg);
+	TSecureId clientSid = aMsg.SecureId();
+	
+	TBool vaildSid = EFalse;
+    RArray<TSecureId> installerSids;
+    CleanupClosePushL(installerSids);
+    if (iRequestImpl->GetSidsForSoftwareTypeL(softwareTypeName, installerSids))
+        {
+        TInt count = installerSids.Count();
+        for (TInt i = 0; i < count; i++)
+            {
+            if (clientSid == installerSids[i])
+                {
+                vaildSid = ETrue;
+                break;
+                }
+            }
+        }
+    CleanupStack::PopAndDestroy(2, softwareTypeName);
+	
+	if (vaildSid)	
+		return EPass;	
+
+	DEBUG_PRINTF(_L("Client Sid is not a valid one software type!"));	
+	return EFail;
+	}
+
+CPolicyServer::TCustomResult CScrServer::CheckAllowedFilePathL(const RMessage2& aMsg)
+	{
+	HBufC* fileName = CScrRequestImpl::ReadFileNameFromMsgLC(aMsg);
+	
+	// Retrieve the required capabilities for write access to this path
+	TCapabilitySet requiredCapabilities = SecCommonUtils::FileModificationRequiredCapabilitiesL(*fileName, aMsg.SecureId());
+	
+	TBool result = EFalse;
+	TBool allFilesRequired = requiredCapabilities.HasCapability(ECapabilityAllFiles);
+	TBool tcbRequired = requiredCapabilities.HasCapability(ECapabilityTCB);
+	
+	// Test whether the client has at least one of the required capabilities
+	if (allFilesRequired)
+		result = aMsg.HasCapability(ECapabilityAllFiles);
+	if (!result && tcbRequired)
+		result = aMsg.HasCapability(ECapabilityTCB);
+	if (!allFilesRequired && !tcbRequired)
+		result = ETrue;
+	
+	CleanupStack::PopAndDestroy(fileName);
+	return result ? EPass : EFail;
+	}
+
+CPolicyServer::TCustomResult CScrServer::CheckClientIsInstallerL(const RMessage2& aMsg)
+	{
+	TSecureId clientSid = aMsg.SecureId();
+	DEBUG_PRINTF2(_L("The client SID is 0x%X"), clientSid.iId);
+	TBool isInstallerSid = iRequestImpl->IsInstallerOrExecutionEnvSidL(clientSid);
+	return isInstallerSid ? EPass : EFail;
+	}
+
+CPolicyServer::TCustomResult CScrServer::CheckCommonComponentPropertySettableL(const RMessage2& aMsg, TCapability aRequiredCapability)
+	{
+	// Setting a common component property is allowed either for the owning installer or for a process with corresponding capability
+	if (CheckComponentIdMatchingEnvironmentL(aMsg) == EPass)
+		return EPass;
+	return aMsg.HasCapability(aRequiredCapability)? EPass : EFail;
+	}
+
+CPolicyServer::TCustomResult CScrServer::CustomSecurityCheckL(const RMessage2& aMsg, TInt& /*aAction*/, TSecurityInfo& /*aMissing*/)
+	{	
+	// SCS framework adds its own bitmask to the function id - we need to strip it in order to detect the actual function invoked
+	TInt functionId = StripScsFunctionMask(aMsg.Function());
+
+	switch (functionId)
+		{
+		case ECreateTransaction:
+		case ERollbackTransaction:
+		case ECommitTransaction:
+			return CheckClientIsInstallerL(aMsg);
+		case EAddComponent:
+		case EAddComponentDependency:
+		case EDeleteComponentDependency:
+			return CheckSoftwareNameMatchingEnvironmentL(aMsg);
+		case ERegisterComponentFile:
+		case ESetFileStringProperty:
+		case ESetFileNumericProperty:
+		case EDeleteFileProperty:
+		case EUnregisterComponentFile:
+			// For file registration we check that the client is actually allowed to modify files under this location
+			// We do not check for the installer SID, since if the client can write to this location, then registering this location for other components
+			// does not pose additional risk			
+			return CheckAllowedFilePathL(aMsg);	
+		case ESetComponentLocalizableProperty:
+		case ESetComponentNumericProperty:
+		case ESetComponentBinaryProperty:
+		case ESetComponentName:
+		case ESetComponentVendor:
+		case ESetComponentVersion:
+		case ESetComponentSize:
+		case EDeleteComponentProperty:
+		case ESetScomoState:
+		case ESetIsComponentPresent:
+			return CheckComponentIdMatchingEnvironmentL(aMsg);
+		case EDeleteComponent:			
+			return CheckDeleteComponentAllowedL(aMsg);
+		case ESetIsComponentRemovable:
+			return CheckCommonComponentPropertySettableL(aMsg, ECapabilityAllFiles);
+		case ESetIsComponentDrmProtected:
+		case ESetIsComponentHidden:
+		case ESetIsComponentKnownRevoked:
+		case ESetIsComponentOriginVerified:		
+			return CheckCommonComponentPropertySettableL(aMsg, ECapabilityWriteDeviceData);
+		case EAddApplicationEntry:
+		case EDeleteApplicationEntries:
+			return CheckComponentIdMatchingEnvironmentL(aMsg);
+		case EDeleteApplicationEntry:
+		    return CheckComponentIdMatchingEnvironmentL(aMsg, ETrue);
+		default:
+			DEBUG_PRINTF2(_L("Unknown function was invoked in CustomSecurityCheck - %d"), functionId);							
+			__ASSERT_DEBUG(0, User::Invariant());
+			return EFail;
+		}
+	}
+
+void CScrServer::ReconnectL()
+	{
+	DeleteObjectZ(iRequestImpl);	
+	iRequestImpl = CScrRequestImpl::NewL(iFs, iDatabaseFile, iJournalFile);	
+	}
+
+void CScrServer::AddSubsessionOwnerL(CScrSession* aSession)
+	{
+	iSubsessionOwners.InsertInAddressOrderAllowRepeatsL(aSession);
+	}
+
+void CScrServer::RemoveSubsessionOwner(CScrSession* aSession)
+	{
+	TInt index = iSubsessionOwners.FindInAddressOrder(aSession);
+	if(KErrNotFound != index)
+		iSubsessionOwners.Remove(index);
+	}
+
+TBool CScrServer::IsTheOnlySubsessionOwner(CScrSession* aSession)
+	{
+	TInt firstElementIdx = 0;
+	TInt lastElementIdx = iSubsessionOwners.Count();
+	// if both first element and the last element in the array is the provided session
+	// it means that all active subsessions is owned by this session. 
+	if(firstElementIdx == iSubsessionOwners.SpecificFindInAddressOrder(aSession, EArrayFindMode_First) &&
+	   lastElementIdx == iSubsessionOwners.SpecificFindInAddressOrder(aSession, EArrayFindMode_Last))
+		{
+		return ETrue;
+		}
+	return EFalse; 
+	}
+
+TInt CScrServer::SubsessionCount()
+	{
+	return iSubsessionOwners.Count();
+	}
+
+void CScrServer::SetTransactionOwner(CScrSession* aSession)
+	{
+	iTransactionOwningSession = aSession;
+	}
+
+
+TBool CScrServer::IsTransactionInProgress()
+	{
+	if(iTransactionOwningSession)
+		return ETrue;
+	else 
+		return EFalse;
+	}
+
+
+TBool CScrServer::IsTransactionOwner(CScrSession* aSession)
+	{	
+	__ASSERT_ALWAYS(aSession, User::Invariant());
+	if(aSession == iTransactionOwningSession) 
+		return ETrue;
+	else 
+		return EFalse;
+	}
+
+void CScrServer::DoPreHeapMarkOrCheckL()
+/**
+   This function is called by the framework just before settingchecking a heap mark. We need to compress/free memory
+   down to a state which should be the same both before and after the test operations.
+*/
+{
+#ifdef _DEBUG
+iSubsessionOwners.Compress();
+DeleteObjectZ(iRequestImpl);
+#endif
+}
+
+void CScrServer::DoPostHeapMarkOrCheckL()
+/**
+   This function is called by the framework just before settingchecking a heap mark. We need to compress/free memory
+   down to a state which should be the same both before and after the test operations.
+*/
+{
+#ifdef _DEBUG
+this->ReconnectL();
+#endif
+}