diff -r 5cc91383ab1e -r 7333d7932ef7 installationservices/swcomponentregistry/source/server/scrserver.cpp --- /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 +#include "scrhelperclient.h" +#include + +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 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 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 +}