authorisation/userpromptservice/policies/source/policycache.cpp
changeset 8 35751d3474b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/authorisation/userpromptservice/policies/source/policycache.cpp	Thu Sep 10 14:01:51 2009 +0300
@@ -0,0 +1,349 @@
+/*
+* Copyright (c) 2007-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: 
+*
+*/
+
+
+#include "policycache.h"
+#include "policylist.h"
+#include "policyreader.h"
+#include "promptrequest.h"
+#include "serviceconfig.h"
+#include <f32file.h>
+#include <ups/upserr.h>
+#include "upslog.h"
+
+using namespace UserPromptService;
+
+EXPORT_C CPolicyCache* CPolicyCache::NewL(RFs& aFs, const TDesC& aPolicyPath)
+/**
+Creates a new policy cache.
+@param aFs			The file server session used to load policy files.\n
+					Ownership is not transferred.
+@param aPolicyPath	The path of the policy files (minus the drive). It must be
+					in the following form "\private\sid\policies\"
+@return				A pointer to the new policy cache object.
+*/
+	{
+	CPolicyCache* self = new(ELeave) CPolicyCache(aFs);
+	CleanupStack::PushL(self);
+	self->ConstructL(aPolicyPath);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CPolicyCache::CPolicyCache(RFs& aFs) 
+/**
+Constructor
+@param aFs	The file server session used to load policy files.
+*/
+	: iFs(aFs)
+	{	
+	}
+
+CPolicyCache::~CPolicyCache()
+/**
+Destructor
+*/
+	{
+	iPolicyLists.ResetAndDestroy();
+	delete iPolicyPath;
+	}
+
+void CPolicyCache::ConstructL(const TDesC& aPolicyPath)
+/**
+Second phase constructor, resolves the system drive.
+@param aPolicyPath	The directory where the policy files are stored.
+*/
+	{
+	iPolicyPath = aPolicyPath.AllocL();
+	iSystemDriveChar = iFs.GetSystemDriveChar();
+	}
+
+EXPORT_C const CPolicy* CPolicyCache::MatchL(const CPromptRequest& aRequest)
+/**
+Finds the first policy that matches the request.
+
+@param	aRequest	The request data from the system server.
+@return				A copy of the policy object to apply to the request. If a policy
+					file exists but no policy is defined then a default policy object
+					is returned that current request to be accepted or denied.
+					
+@leave KErrUpsMissingPolicyFile	If no policy file is found for the requested server sid and service id.								
+@leave KErrUpsBadPolicyFile		If an error occured whilst parsing a policy file.
+*/
+	{
+	CPolicyList::TId id(aRequest.ServerSid(), aRequest.ServiceId());		
+	const CPolicyList* list = PolicyList(id);
+	
+	if (!list)
+		{
+		// Policy list not found so try and load it. This
+		// leaves if a UPS policy file is not found.
+		list = LoadPolicyListL(id);				
+		}
+		
+	ASSERT(list);	
+	return list->Match(aRequest);
+	}
+
+const CPolicyList* CPolicyCache::PolicyList(const CPolicyList::TId& aId) const
+/**
+Gets the specified policy list if it is loaded.
+@param	The ID of the policy list.
+@return A pointer to the policy list if it is loaded; otherwise, is returned.
+*/
+	{
+	TInt count = iPolicyLists.Count();
+	for (TInt i = 0; i < count; ++i) // Check if policy list is in the cache
+		{
+		if (iPolicyLists[i]->Id() == aId)
+			{
+			return iPolicyLists[i];			
+			}
+		}
+	return 0;
+	}
+
+CPolicyList* CPolicyCache::LoadPolicyListL(const CPolicyList::TId& aId)
+/**
+Loads a list of policies from the policy file for the specified system server and service.
+@param	aId	A tuple of the system server SID and service UID that identifies a policy file.
+
+@return		The list of policies, or N
+@leave		KErrUpsBadPolicyFile if an error occured whilst parsing a policy file.
+			KErrUpsMissingPolicyFile if the policy file was not found on the Z or the system drive.
+*/
+	{
+	RBuf fn;
+	fn.CreateL(KMaxFileName);
+	CleanupClosePushL(fn);
+	
+	LocatePolicyFileL(fn, aId);		
+	
+	CPolicyList* l(0);
+	TRAPD(err, l = ParseListL(aId, fn));			
+	if (err != KErrNone && err != KErrNoMemory)
+		{
+		DEBUG_PRINTF2(_L("Unable to parse %S"), &fn);
+		err = KErrUpsBadPolicyFile;
+		
+		if (fn[0] == 'Z')
+			{			
+			DEBUG_PRINTF2(_L("Unable to parse %S"), &fn);
+			User::Panic(KUpsPoliciesPanicCat, EUpsPoliciesCorruptRomPolicy);			
+			}
+		else {
+			// If we failed to read the policy file from the system 
+			// drive then try the Z drive.
+			fn[0] = 'Z';
+			TRAP(err, l = ParseListL(aId, fn));
+			if (err == KErrNone)
+				{
+				DEBUG_PRINTF2(_L("Ignoring corrupt policy file on system drive. Loading %S"), &fn);
+				}
+			else if (err != KErrNotFound && err != KErrNoMemory)
+				{
+				DEBUG_PRINTF2(_L("Unable to parse %S"), &fn);
+				User::Panic(KUpsPoliciesPanicCat, EUpsPoliciesCorruptRomPolicy);
+				}			
+			}
+		}
+	User::LeaveIfError(err);
+	
+	CleanupStack::PushL(l);
+	iPolicyLists.AppendL(l);
+	CleanupStack::Pop(l);		
+	CleanupStack::PopAndDestroy(&fn);
+	return l;
+	}
+
+void CPolicyCache::LocatePolicyFileL(TDes& aPolicyFileName, const CPolicyList::TId& aId)
+/**
+Determines whether the policy file should be loaded from the Z drive 
+or the system drive and returns the filename.
+
+@param aPolicyFileName	Descriptor to populate with the filename.
+@param aId				The id of the policy file to load.
+						
+@leave KErrUpsMissingPolicyFile The policy file was not found on either the Z drive
+								or the system drive.
+*/	
+	{
+	_LIT(KDriveSpec, "!:");
+		
+	aPolicyFileName.Zero();
+	aPolicyFileName.Append(KDriveSpec);
+	aPolicyFileName.Append(*iPolicyPath);
+	aId.AppendNameToPath(aPolicyFileName);
+	
+	// System drive eclipses Z drive	
+	aPolicyFileName[0] = iSystemDriveChar;
+	if (! FileExistsL(aPolicyFileName))
+		{
+		aPolicyFileName[0] = 'Z';
+		if (! FileExistsL(aPolicyFileName))
+			{
+			DEBUG_PRINTF3(_L8("No policy file for system server sid = 0x%08x, service id = 0x%08x"),
+				aId.iServerSid.iId, aId.iServiceId.iUid);
+			User::Leave(KErrUpsMissingPolicyFile);	
+			}
+		}
+	}
+
+CPolicyList* CPolicyCache::ParseListL(const CPolicyList::TId& aId, const TDesC& aPolicyFileName)
+/**
+Parses a policy file and constructs a policy list object.
+
+@param	aId				The policy file id that will be used to locate the policy list within
+						the policy cache.
+@param	aPolicyFileName	The absolute path of the policy file to parse.
+@return The new policy list object.
+*/
+	{
+	CPolicyReader* r = CPolicyReader::NewLC(iFs, aPolicyFileName);
+	CPolicyList* l = CPolicyList::NewL(aId, *r);	
+	CleanupStack::PopAndDestroy(r);
+	return l;
+	}
+
+EXPORT_C void CPolicyCache::ServiceConfigL(const TSecureId& aServerSid, RArray<TServiceConfig>& aConfigs)
+/**
+Loads the service configuration data from the policy files for every service provided
+by a given system server.
+@param	aServerSid	The secure id of the system server.
+@param	aConfigs	The RArray to populate with the configuration data.
+*/
+	{				
+	RArray<TUint> services;
+	CleanupClosePushL(services);
+	
+	DEBUG_PRINTF2(_L8("Loading service configuration for system server 0x%08x"), aServerSid.iId);
+	
+	FindServicesL(aServerSid, services);
+	TInt numServices = services.Count();
+	
+	// Load the services
+	for (TInt i = 0; i < numServices; ++i)
+		{
+		CPolicyList::TId id(aServerSid, TUid::Uid(services[i]));		
+		const CPolicyList* list = PolicyList(id);
+		if (list)
+			{
+			// Use in-memory service configuration
+			aConfigs.AppendL(list->ServiceConfig());
+			}
+		else 
+			{
+			// Load policy file into cache
+			CPolicyList* loadedList = LoadPolicyListL(id);
+			aConfigs.AppendL(loadedList->ServiceConfig());
+			}
+		}						
+	CleanupStack::PopAndDestroy(&services);
+	}
+
+void CPolicyCache::FindServicesL(const TSecureId& aServerSid, RArray<TUint>& aServices)
+/**
+Finds all of the policy files on Z drive and C drive for this system server		
+A wildcard string is used to filter out policy files for other system servers.
+
+@param aServerSid	The secure id of the system server.
+@param aServices	The array of service ids to populate.
+*/
+	{
+	_LIT(KFilenameTemplate, "ups_%08x_????????.rsc");
+	TBuf<32> pattern;
+	pattern.AppendFormat(KFilenameTemplate, aServerSid.iId);
+		
+	RBuf fn;	// Store current file/directory name.
+	fn.CreateL(KMaxFileName);
+	CleanupClosePushL(fn);	
+	for (TInt i = 0; i < 2; ++i)	
+		{
+		TUint driveChar = (i == 0) ? TChar('Z') : iSystemDriveChar;
+		
+		fn.Zero();
+		_LIT(KDirFormat, "%c:%S");
+		fn.AppendFormat(KDirFormat, driveChar, &*iPolicyPath);
+		
+		CDir* dir(0);	
+		TInt err = iFs.GetDir(fn, KEntryAttNormal, ESortNone, dir);
+		if (err == KErrPathNotFound) 
+			{
+			continue;
+			}
+		User::LeaveIfError(err);
+		CleanupStack::PushL(dir);
+		
+		// Find the services
+		TInt count = dir->Count();
+		for (TInt j = 0; j < count; ++j)
+			{
+			const TEntry& e((*dir)[j]);
+			if (e.iName.MatchF(pattern) >= 0)
+				{
+				fn.Zero();
+				_LIT(KFileFormat, "%C:%S%S");
+				fn.AppendFormat(KFileFormat, driveChar, iPolicyPath, &e.iName);
+								
+				CPolicyList::TId policyListId;
+				TRAP(err, CPolicyList::TId::IdL(fn, policyListId))
+				if (err == KErrNoMemory)
+					{
+					// Do not let OOM cause us to ignore policy files
+					User::Leave(err);
+					}
+				if (err == KErrNone)
+					{
+					// Ensure there are no duplicate service configs due to eclisped policy files.
+					err = aServices.InsertInOrder(static_cast<TUint>(policyListId.iServiceId.iUid));
+					if (err != KErrAlreadyExists)
+						{
+						User::LeaveIfError(err);
+						}
+					}
+				else
+					{
+					DEBUG_PRINTF2(_L("%S does not match UPS policy filename rules"), &fn);
+					}
+				}
+			// Policy file is for a different system server
+			}		
+		CleanupStack::PopAndDestroy(dir);
+		}	
+	CleanupStack::PopAndDestroy(&fn);
+	}
+
+TBool CPolicyCache::FileExistsL(const TDesC& aFileName)
+/**
+Checks whether a file exists.
+- If the FileName corresponds to a directory then EFalse is returned.
+
+@param	aFileName	The absolute path of the file to check.
+@return ETrue, if aFileName exists; otherwise, EFalse is returned.
+*/
+	{
+	TBool exists = EFalse;
+	TEntry* e = new(ELeave) TEntry();		
+	TInt err = iFs.Entry(aFileName, *e);
+	if (err == KErrNone && ! e->IsDir())
+		{
+		exists = ETrue;			
+		}
+	delete e;
+	return exists;
+	}
+