Symbian3/SDK/Source/GUID-43080A86-72D3-5422-953E-A5EF79961D7B.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Fri, 11 Jun 2010 15:24:34 +0100
changeset 9 59758314f811
parent 7 51a74ef9ed63
permissions -rw-r--r--
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&amp; aRequest, const CPolicy&amp; aPolicy, 
    RPointerArray&lt;CFingerprint&gt;&amp; aFingerprints, const CClientEntity*&amp; aClientEntity, 
    const TAny*&amp; aDialogCreatorParams, TRequestStatus&amp; aStatus)
    {
    iRequest = &amp;aRequest;
    iPolicy = &amp;aPolicy;
    iFingerprints = &amp;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 = &amp;aStatus;
    aStatus = KRequestPending;
    
    // Kick off policy evaluator state machine
    iStatus = KRequestPending;
    TRequestStatus* status = &amp;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-&gt;Reset();
    const TDesC&amp; d = iRequest-&gt;Destination();
    TPtrC8 p(reinterpret_cast&lt;const TUint8*&gt;(d.Ptr()), d.Length() * 2);
    TPtrC8 h(iDigest-&gt;Hash(p));
    
    CFingerprint* f = CFingerprint::NewLC(h, d);
    iFingerprints-&gt;AppendL(f);
    CleanupStack::Pop(f);

    // An empty fingerprint may be used for decisions that apply to
    // all destinations.
    f = CFingerprint::NewLC(KNullDesC8, KNullDesC);
    iFingerprints-&gt;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&amp; aDecision, TUint&amp; 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 &amp;&amp; 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 &lt;ecom/implementationproxy.h&gt;
#include &lt;ups/cliententity.h&gt;
#include &lt;ups/fingerprint.h&gt;
#include &lt;ups/upsdb.h&gt;

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-&gt;ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

static const TImplementationProxy ImplementationTable[] = 
    {
    IMPLEMENTATION_PROXY_ENTRY(KRefPolicyEvaluatorImplementationId, CRefPolicyEvaluator::CreatePolicyEvaluatorL)
    };

EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt&amp; 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-&gt;Reset();
    const TDesC&amp; d = iRequest-&gt;Destination();
    TPtrC8 p(reinterpret_cast&lt;const TUint8*&gt;(d.Ptr()), d.Length() * 2);
    TPtrC8 h(iDigest-&gt;Hash(p));
    
    CFingerprint* f = CFingerprint::NewLC(h, d);
    iFingerprints-&gt;AppendL(f);
    CleanupStack::Pop(f);

    // An empty fingerprint may be used for decisions that apply to
    // all destinations.
    f = CFingerprint::NewLC(KNullDesC8, KNullDesC);
    iFingerprints-&gt;AppendL(f);
    CleanupStack::Pop(f);
        
    User::RequestComplete(iClientStatus, KErrNone);
    }

void CRefPolicyEvaluator::GenerateFingerprints(
    const CPromptRequest&amp; aRequest, const CPolicy&amp; aPolicy, 
    RPointerArray&lt;CFingerprint&gt;&amp; aFingerprints, const CClientEntity*&amp; aClientEntity, 
    const TAny*&amp; aDialogCreatorParams, TRequestStatus&amp; aStatus)
    {
    iRequest = &amp;aRequest;
    iPolicy = &amp;aPolicy;
    iFingerprints = &amp;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 = &amp;aStatus;
    aStatus = KRequestPending;
    
    // Kick off policy evaluator state machine
    iStatus = KRequestPending;
    TRequestStatus* status = &amp;iStatus;
    SetActive();
    User::RequestComplete(status, KErrNone);
    }

TBool CRefPolicyEvaluator::ForcePromptL(const CDecisionRecord&amp; aDecision, TUint&amp; 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 &amp;&amp; aDecision.iEvaluatorInfo == 0);
    }
</codeblock> </section>
</conbody></concept>