Week 23 contribution of PDK documentation content. See release notes for details. Fixes bugs Bug 2714, Bug 462.
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-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:
-->
<!DOCTYPE concept
PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-43080A86-72D3-5422-953E-A5EF79961D7B" xml:lang="en"><title>Writing
a UPS Policy Evaluator</title><prolog><metadata><keywords/></metadata></prolog><conbody>
<section id="GUID-56EDF170-1A32-4275-8799-99D13C485E1E"><title>Introduction</title> <p>Policy Evaluators are ECOM plug-ins.
They allow security decisions to be specific to the data on which the service
acts instead of simply granting full access to the service, for example "Allow
application X to send SMS messages to 01234567". This is supported through
the fingerprint functionality. They allow a security decision to be specific
to an individual script executing within a scripting host. This is supported
through the client entity field. And they allow a prompt to be displayed even
if the user selected "Always" or "Never". This could be based on a usage threshold
or simply as additional confirmation if the user selected "Never". This is
supported through the force prompt functionality. </p> <p> <b>Note</b>: when
a user selects “Never” or “Always”, the UPS creates a record in a decision
database. This record identifies the system server UID, service UID, client
SID, client entity name (name of an entity running within a client process,
for example, a script identifier) and a "fingerprint" for a given decision. </p> <p>The
purpose of a Policy Evaluator is to allow device creators to optionally customise
the behaviour of the UPS at run-time. Policy Evaluators may: </p> <ul>
<li id="GUID-1D5DD614-02E3-56AA-A0A6-A694E2311A0E"><p>Allow security decisions
to be specific to the data on which the service acts instead of simply granting
full access to the service, for example "Allow application X to send SMS messages
to 01234567". This is supported via the fingerprint functionality. </p> </li>
<li id="GUID-5B5E3EB4-5C93-5E4E-BB6E-39F889AD3610"><p>Allow a security decision
to be specific to an individual script executing within a scripting host.
This is supported via the client entity field. </p> </li>
<li id="GUID-8B26DA57-A9DF-5D99-A259-2E6DF7C4DCCE"><p>Allow a prompt to be
displayed even if the user selected "Always" or "Never". This could be based
on a usage threshold or simply as additional confirmation if the user selected
"Never". This is supported via the force prompt functionality. </p> </li>
</ul> </section>
<section id="GUID-CCBB139D-0F1C-4AD4-B2F2-062CF660A0DE"><title>Procedure</title> <p>Writing policy evaluator includes the
following: </p> <ol id="GUID-F50174F6-3619-545A-8844-D4DA64B1B339">
<li id="GUID-246EF2AB-23D9-5B1B-BC4C-8CCFB545C307"><p>Generating fingerprints </p> </li>
<li id="GUID-4427FF70-9461-566A-8567-FC6EEF879475"><p>Forcing prompts </p> </li>
<li id="GUID-703D9B83-78A0-5EA6-8D1C-685D2BC847EA"><p>Defining default policy
evaluator </p> </li>
</ol> <p>Policy evaluators implement the <codeph>CPolicyEvaluator</codeph> interface. </p> <p><b>Generating
fingerprints</b> </p> <p>The key task of the policy evaluator is to generate
fingerprints. A fingerprint is a collection of data describing the service
being requested. The fingerprint usually includes the <codeph>destination</codeph> string,
for example a telephone number, supplied by the service that is matched to
the <codeph>destination</codeph> string of a policy in the policy file. </p> <p>The
policy evaluator must implement the <codeph>GenerateFingerprints()</codeph> function,
which is a pure virtual function, declared in the <xref href="GUID-FDE91CAC-1588-3EED-B509-08168F4B881B.dita"><apiname>CPolicyEvaluator</apiname></xref> base
class. The function is asynchronous to allow the implementation to call other
server processes. </p> <p>The following table describes the parameters for
the <codeph>GenerateFingerprints()</codeph> function: </p> <table id="GUID-963D89B8-EB90-5668-8A08-588EF1E94C43">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<thead>
<row>
<entry>Parameter</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><p> <codeph>aRequest</codeph> </p> </entry>
<entry><p>Data that the system server provides to the UPS, including the ClientSid,
ServerSid and ServiceId. </p> </entry>
</row>
<row>
<entry><p> <codeph>aPolicy</codeph> </p> </entry>
<entry><p>Details of the policy for the service. </p> </entry>
</row>
<row>
<entry><p> <codeph>aFingerprints</codeph> </p> </entry>
<entry><p>Array of fingerprints. </p> </entry>
</row>
<row>
<entry><p> <codeph>aClientEntity</codeph> </p> </entry>
<entry><p>Details of client entity (will be null if the client process is
not an execution host or the policy evaluator does not support client entities). </p> </entry>
</row>
<row>
<entry><p> <codeph>aDialogCreatorParams</codeph> </p> </entry>
<entry><p>Opaque data, which can be any other information for use in the fingerprint
or to be displayed in the dialog. </p> </entry>
</row>
<row>
<entry><p> <codeph>aStatus</codeph> </p> </entry>
<entry><p>The request status used to contain completion information for the
function. </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p>The following code fragment is a sample implementation of the <codeph>GenerateFingerprints()</codeph> function. </p> <codeblock id="GUID-B8555FDF-8BDD-5D22-AA20-AA9A4B35148A" xml:space="preserve">void CRefPolicyEvaluator::GenerateFingerprints(
const CPromptRequest& aRequest, const CPolicy& aPolicy,
RPointerArray<CFingerprint>& aFingerprints, const CClientEntity*& aClientEntity,
const TAny*& aDialogCreatorParams, TRequestStatus& aStatus)
{
iRequest = &aRequest;
iPolicy = &aPolicy;
iFingerprints = &aFingerprints;
// This OUT parameter *could* be set to point to data structure
// owned by this policy evaluator that is read by the dialog-creator.
aDialogCreatorParams = 0;
// The client entity field only needs to be set if the policy evaluator
// is designed to identify scripts/non-native applications being executed
// by the client application.
aClientEntity = 0;
iClientStatus = &aStatus;
aStatus = KRequestPending;
// Kick off policy evaluator state machine
iStatus = KRequestPending;
TRequestStatus* status = &iStatus;
SetActive();
User::RequestComplete(status, KErrNone);
}
</codeblock> <p> <codeph>RunL()</codeph> is called when the request completes.
The fingerprint is created and appended to the fingerprint array in <codeph>RunL()</codeph>.
The following example shows a hash of a destination being created for a fingerprint
as well as an empty fingerprint for decisions that apply to all destinations. </p> <codeblock id="GUID-EB57F6E0-C3B2-5CDC-B9FF-A570B73B4C74" xml:space="preserve">void CRefPolicyEvaluator::RunL()
{
// Create most specific hash first i.e. HASH(destination)
// Information from the opaque data supplied by the system server
// may also be used.
// N.B. The UPS does not require the fingerprint to be a hash. However,
// the fingerprint is limited to 32 bytes.
iDigest->Reset();
const TDesC& d = iRequest->Destination();
TPtrC8 p(reinterpret_cast<const TUint8*>(d.Ptr()), d.Length() * 2);
TPtrC8 h(iDigest->Hash(p));
CFingerprint* f = CFingerprint::NewLC(h, d);
iFingerprints->AppendL(f);
CleanupStack::Pop(f);
// An empty fingerprint may be used for decisions that apply to
// all destinations.
f = CFingerprint::NewLC(KNullDesC8, KNullDesC);
iFingerprints->AppendL(f);
CleanupStack::Pop(f);
User::RequestComplete(iClientStatus, KErrNone);
}
</codeblock> <p><b>Forcing prompts</b> </p> <p>You can implement the <codeph>ForcePromptL()</codeph> function
to force a prompt, even if the UPS has found a persistent decision for the
request in the decision database. It may be desirable to force a prompt in
some cases such as: </p> <ul>
<li id="GUID-4C9DDFB3-C358-534F-8E65-42E1BC672D64"><p>if a threshold has been
reached, for example the number of MMS messages sent on a particular day </p> </li>
<li id="GUID-5D5E02E5-DA19-5A30-8071-CD64631FBEAD"><p>if a phone user has
selected "Never", because denying a request to a non-UPS-aware application
may cause it to fail — the user may not realise that the previous selection
of "Never" has caused the failure or may not know how to find the management
application to revert the decision </p> </li>
</ul> <p>The UPS invokes the <codeph>ForcePromptL()</codeph> function after
a matching record is found in the database. The <codeph>ForcePromptL()</codeph> function
is defined in the <codeph>CPolicyEvaluator</codeph> base class. The implementation
in the base class always returns <codeph>EFalse</codeph>. To force a prompt,
device creators need to override this function and return <codeph>ETrue</codeph>.
A sample implementation is as follows. The <codeph>aNewEvaluatorInfo</codeph> field
is a policy evaluator defined 32-bit field. It could be used to store usage
thresholds or as a flag that indicates that the prompt has already been forced. </p> <codeblock id="GUID-4E60DCA5-7F25-5FC7-B173-05E1A15FCEE6" xml:space="preserve">TBool CRefPolicyEvaluator::ForcePromptL(const CDecisionRecord& aDecision, TUint& aNewEvaluatorInfo)
{
// In this example, if the user selects Never, then they are prompted
// once more in-case they did not intend to select Never.
// The "Evaluator Info" field is used to ensure the prompt is only forced once.
//
// The base class implementation (CPolicyEvaluator::ForcePromptL)
// always returns EFalse.
aNewEvaluatorInfo = 1;
return (aDecision.iResult == 0 && aDecision.iEvaluatorInfo == 0);
}
</codeblock> <p><b>Defining default policy evaluator</b> </p> <p>If device
creators do not define a policy evaluator, a default (internal) policy evaluator
is returned. The default policy evaluator returns a single, null fingerprint.
The default policy evaluator does not override the <codeph>ForcePromptL()</codeph> API. </p> </section>
<section id="GUID-987ECDA9-5728-4A7A-AB38-D58A7CC097AC"><title> Upgrading policy evaluators </title> <p>A policy evaluator
can be overwritten or eclipsed without restarting the UPS, if it is delivered
through an appropriately signed upgrade. </p> <ul>
<li id="GUID-086FABB6-13C0-5D98-8B2A-1D38BD620EB5"><p>The ECOM plug-in will
be reloaded only when there are no active <codeph>RUpsSubsession::Authorise()</codeph> requests. </p> </li>
<li id="GUID-CD95EB32-9438-5AA1-BA80-8C90DC304642"><p>The decision records
are not deleted if the policy evaluator is changed. If the policy evaluator
is not backwards compatible then new policy files with a new <codeph>majorversion</codeph> number
should be delivered. </p> </li>
<li id="GUID-DC1804B8-A052-52AC-96DC-32C3BBADE2A8"><p>SWI Observer informs
the UPS that the plug-ins may have changed whenever Software Install modifies <filepath>sys\bin</filepath> on
the system drive. There is no need to explicitly register changes to plug-ins. </p> </li>
</ul> </section>
<section id="GUID-48624948-C1C9-4DEA-A6E1-6E4B9AC72E8E"><title> Policy evaluator example</title> <p>The following code shows
an example of a full implementation of the policy evaluator file: </p> <codeblock id="GUID-D1615A8D-334C-5718-BFD6-EC3004A09F3A" xml:space="preserve">#include "refpolicyevaluator.h"
#include <ecom/implementationproxy.h>
#include <ups/cliententity.h>
#include <ups/fingerprint.h>
#include <ups/upsdb.h>
using namespace UserPromptService;
static const TUint KRefPolicyEvaluatorImplementationId = 0x10285814;
CPolicyEvaluator* CRefPolicyEvaluator::CreatePolicyEvaluatorL()
/**
Factory method that instantiates a new policy evaluator ECOM plug-in.
@return A pointer to the new reference policy evaluator object.
*/
{
CRefPolicyEvaluator* self = new (ELeave)CRefPolicyEvaluator();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
static const TImplementationProxy ImplementationTable[] =
{
IMPLEMENTATION_PROXY_ENTRY(KRefPolicyEvaluatorImplementationId, CRefPolicyEvaluator::CreatePolicyEvaluatorL)
};
EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
/**
Standard ECOM factory
*/
{
aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
return ImplementationTable;
}
CRefPolicyEvaluator::CRefPolicyEvaluator()
/**
Constructor
*/
: CPolicyEvaluator()
{
CActiveScheduler::Add(this);
}
CRefPolicyEvaluator::~CRefPolicyEvaluator()
/**
Destructor
*/
{
Deque();
delete iDigest;
}
void CRefPolicyEvaluator::ConstructL()
/**
Second phase constructor, creates the message digest
*/
{
iDigest = CMessageDigestFactory::NewDigestL(CMessageDigest::EMD5);
}
// From CActive
void CRefPolicyEvaluator::DoCancel()
{
// Logically should Cancel the internal outstanding requst, but
// currently GenerateFingerprints has already completed it.
// And need to complete the clients request
if (iClientStatus)
{
User::RequestComplete(iClientStatus, KErrCancel);
}
}
TInt CRefPolicyEvaluator::RunError(TInt aError)
{
if (iClientStatus)
{
User::RequestComplete(iClientStatus, aError);
}
return KErrNone;
}
void CRefPolicyEvaluator::RunL()
{
// Create most specific hash first i.e. HASH(destination)
// Information from the opaque data supplied by the system server
// may also be used.
// N.B. The UPS does not require the fingerprint to be a hash. However,
// the fingerprint is limited to 32 bytes.
iDigest->Reset();
const TDesC& d = iRequest->Destination();
TPtrC8 p(reinterpret_cast<const TUint8*>(d.Ptr()), d.Length() * 2);
TPtrC8 h(iDigest->Hash(p));
CFingerprint* f = CFingerprint::NewLC(h, d);
iFingerprints->AppendL(f);
CleanupStack::Pop(f);
// An empty fingerprint may be used for decisions that apply to
// all destinations.
f = CFingerprint::NewLC(KNullDesC8, KNullDesC);
iFingerprints->AppendL(f);
CleanupStack::Pop(f);
User::RequestComplete(iClientStatus, KErrNone);
}
void CRefPolicyEvaluator::GenerateFingerprints(
const CPromptRequest& aRequest, const CPolicy& aPolicy,
RPointerArray<CFingerprint>& aFingerprints, const CClientEntity*& aClientEntity,
const TAny*& aDialogCreatorParams, TRequestStatus& aStatus)
{
iRequest = &aRequest;
iPolicy = &aPolicy;
iFingerprints = &aFingerprints;
// This OUT parameter *could* be set to point to data structure
// owned by this policy evaluator that is read by the dialog-creator.
aDialogCreatorParams = 0;
// The client entity field only needs to be set if the policy evaluator
// is designed to identify scripts/non-native applications being executed
// by the client application.
aClientEntity = 0;
iClientStatus = &aStatus;
aStatus = KRequestPending;
// Kick off policy evaluator state machine
iStatus = KRequestPending;
TRequestStatus* status = &iStatus;
SetActive();
User::RequestComplete(status, KErrNone);
}
TBool CRefPolicyEvaluator::ForcePromptL(const CDecisionRecord& aDecision, TUint& aNewEvaluatorInfo)
{
// In this example, if the user selects Never, then they are prompted
// once more in-case they did not intend to select Never.
// The "Evaluator Info" field is used to ensure the prompt is only forced once.
//
// The base class implementation (CPolicyEvaluator::ForcePromptL)
// always returns EFalse.
aNewEvaluatorInfo = 1;
return (aDecision.iResult == 0 && aDecision.iEvaluatorInfo == 0);
}
</codeblock> </section>
</conbody></concept>