os/security/authorisation/userpromptservice/server/source/upsserver/upsserver.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/security/authorisation/userpromptservice/server/source/upsserver/upsserver.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,478 @@
     1.4 +/*
     1.5 +* Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies).
     1.6 +* All rights reserved.
     1.7 +* This component and the accompanying materials are made available
     1.8 +* under the terms of the License "Eclipse Public License v1.0"
     1.9 +* which accompanies this distribution, and is available
    1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.11 +*
    1.12 +* Initial Contributors:
    1.13 +* Nokia Corporation - initial contribution.
    1.14 +*
    1.15 +* Contributors:
    1.16 +*
    1.17 +* Description: 
    1.18 +* Implements CUpsServer.	See class and function definitions for
    1.19 +* more information.
    1.20 +*
    1.21 +*/
    1.22 +
    1.23 +
    1.24 +/**
    1.25 + @file
    1.26 +*/
    1.27 +
    1.28 +#include "upsserver.h"
    1.29 +#include "policycache.h"
    1.30 +#include "pluginmanager.h"
    1.31 +#include <ups/upsdbw.h>
    1.32 +#include <ups/cliententity.h>
    1.33 +#include <ups/dialogcreator.h>
    1.34 +#include <ups/fingerprint.h>
    1.35 +#include <ups/policy.h>
    1.36 +#include <ups/policyevaluator.h>
    1.37 +#include <e32property.h>
    1.38 +#include "authoriser.h"
    1.39 +#include <sacls.h>
    1.40 +#include "upsserver_p.h"
    1.41 +
    1.42 +namespace UserPromptService
    1.43 +{
    1.44 +
    1.45 +static const TInt upsPolicyRangeCount = 8;
    1.46 +static const TInt upsPolicyRanges[upsPolicyRangeCount] = 
    1.47 +				{
    1.48 +					0,
    1.49 +					// Range 0 - 0 to EBaseSession-1
    1.50 +					// Not used
    1.51 +					CScsServer::EBaseSession,
    1.52 +					// Range 1 - EBaseSession  to EBaseSession | EMngmntRead-1
    1.53 +					//
    1.54 +					// These codes used to create subsessions and to query the policy
    1.55 +					// authorisation settings.
    1.56 +					//
    1.57 +					// (ESessSubsessFromThreadId/EGetClientConfigLength/EGetClientConfigData)
    1.58 +					//
    1.59 +					CScsServer::EBaseSession | EMngmntRead,
    1.60 +					// Range 2 - EBaseSession | EMngmntRead to EBaseSession | EMngmntDelete - 1
    1.61 +					//
    1.62 +					// Management READ APIs
    1.63 +					//
    1.64 +					CScsServer::EBaseSession | EMngmntDelete,
    1.65 +					// Range 3 - EBaseSession | EMngmntDelete to EBaseSession | EMngmntUpdate - 1
    1.66 +					// Management DELETE API (ie. delete entire database or selected entries).
    1.67 +					//
    1.68 +					CScsServer::EBaseSession | EMngmntUpdate,
    1.69 +					// Range 4 - EBaseSession | EMngmntUpdate to EBaseSession | ESwiObserver - 1
    1.70 +					// Management  UPDATE API (ie. change an existing decision).
    1.71 +					//
    1.72 +					CScsServer::EBaseSession | ESwiObserver,
    1.73 +					// Range 5 - EBaseSession | ESwiObserver to EBaseSubSession - 1
    1.74 +					// SWI observer management API.
    1.75 +					//
    1.76 +					CScsServer::EBaseSubSession,
    1.77 +					// Range 6 - EBaseSubSession to EBaseMustAllow-1
    1.78 +					//
    1.79 +					// System Server APIs
    1.80 +					// Authorise - (ESubsessPreparePrompt/ESubsessExecutePrompt)
    1.81 +					CScsServer::EBaseMustAllow	
    1.82 +					// Range 7 - EBaseMustAllow to KMaxTInt inclusive
    1.83 +					//
    1.84 +					// SCS internal APIs to create subsessions, cancel requests etc.
    1.85 +				};
    1.86 +
    1.87 +static const TUint8 upsPolicyElementsIndex[upsPolicyRangeCount] = 
    1.88 +				{
    1.89 +					CPolicyServer::ENotSupported, // Range 0 - Not used
    1.90 +					CPolicyServer::EAlwaysPass, // Range 1 - Subsess and auth policy
    1.91 +					0, // Range 2 - Management READ APIs
    1.92 +					1, // Range 3 - Management DELETE APIs
    1.93 +					2, // Range 4 - Management UPDATE APIs
    1.94 +					3, // Range 5 - SWI observer APIs
    1.95 +					4, // Range 6 - System Server APIs
    1.96 +					CPolicyServer::EAlwaysPass // Range 7 - SCS internal
    1.97 +				};
    1.98 +
    1.99 +// 0x102836C3 == Swi::KUidSwiObserver.iUid from swiobserver.h BUT we can not include that because SWI is optional
   1.100 +// and we are not!
   1.101 +static const TSecureId KSwiObserverSid(0x102836C3);
   1.102 +static const CPolicyServer::TPolicyElement upsPolicyPolicyElements[5] = 
   1.103 +{
   1.104 +				{_INIT_SECURITY_POLICY_C1(ECapabilityReadDeviceData), CPolicyServer::EFailClient},	
   1.105 +				{_INIT_SECURITY_POLICY_C1(ECapabilityWriteDeviceData), CPolicyServer::EFailClient},	
   1.106 +				{_INIT_SECURITY_POLICY_C1(ECapabilityAllFiles), CPolicyServer::EFailClient},
   1.107 +				{_INIT_SECURITY_POLICY_S0(KSwiObserverSid), CPolicyServer::EFailClient},
   1.108 +				{_INIT_SECURITY_POLICY_C1(ECapabilityProtServ), CPolicyServer::EFailClient}
   1.109 +};
   1.110 +
   1.111 +static const CPolicyServer::TPolicy upsPolicy =
   1.112 +				{
   1.113 +				CPolicyServer::EAlwaysPass, // Allow all connects
   1.114 +				upsPolicyRangeCount,
   1.115 +				upsPolicyRanges,
   1.116 +				upsPolicyElementsIndex,
   1.117 +				upsPolicyPolicyElements,
   1.118 +				};
   1.119 +
   1.120 +_LIT_SECURITY_POLICY_S0(KAllowUpsServer, KUpsServerUid.iUid); //< Only the UPS server can update the P&S flag used to tell clients to re-read client authorisation policies
   1.121 +_LIT_SECURITY_POLICY_C1(KAllowProtServ, ECapabilityProtServ); //< All our system server clients will have ProtServ, so limit reading of the (internal) flag to them.
   1.122 +
   1.123 +CUpsServer* CUpsServer::NewLC()
   1.124 +/**
   1.125 +	Factory function allocates new, initialized instance of
   1.126 +	CUpsServer which is left on the cleanup stack.
   1.127 +
   1.128 +	@return					New, initialized instance of CUpsServer
   1.129 +							which is left on the cleanup stack.
   1.130 + */
   1.131 +	{
   1.132 +	CUpsServer* self = new(ELeave) CUpsServer();
   1.133 +	CleanupStack::PushL(self);
   1.134 +	self->ConstructL();
   1.135 +	return self;
   1.136 +	}
   1.137 +
   1.138 +CUpsServer::CUpsServer()
   1.139 +/**
   1.140 +	Initializes the superclass with this server's version.
   1.141 + */
   1.142 +	:	CScsServer(UserPromptService::Version(), upsPolicy),
   1.143 +		iPolicyCache(iFs),
   1.144 +		iDbHandle(iFs)
   1.145 +	{
   1.146 +	// empty.
   1.147 +	}
   1.148 +
   1.149 +void CUpsServer::ConstructL()
   1.150 +/**
   1.151 +	Second-phase construction initializes the superclass and
   1.152 +	starts the server.
   1.153 + */
   1.154 +	{
   1.155 +	CScsServer::ConstructL(UserPromptService::KShutdownPeriodUs);
   1.156 +	User::LeaveIfError(iFs.Connect());
   1.157 +
   1.158 +	TInt r = RProperty::Define(KUpsServiceConfigProperty, RProperty::EInt, KAllowProtServ, KAllowUpsServer);
   1.159 +	if(r != KErrAlreadyExists)
   1.160 +		{
   1.161 +		User::LeaveIfError(r);
   1.162 +		}
   1.163 +
   1.164 +	iSwiWatcher = CSwiWatcher::NewL(*this);
   1.165 +
   1.166 +	SetupL();
   1.167 +
   1.168 +	StartL(UserPromptService::KUpsServerName);
   1.169 +	}
   1.170 +
   1.171 +void CUpsServer::SetupL()
   1.172 +/**
   1.173 +	Setup memory variables which are not already setup.
   1.174 +	Used during intial construction and after a call to FreeUncompressableMemory.
   1.175 + */
   1.176 +	{
   1.177 +	if(!iPolicyCache.IsOpen())
   1.178 +		{
   1.179 +		iPolicyCache.OpenL();
   1.180 +		}
   1.181 +	if(!iPluginManager)
   1.182 +		{
   1.183 +		iPluginManager = CPluginManager::NewL();
   1.184 +		}
   1.185 +
   1.186 +	// Create/Open the database
   1.187 +	if(!iDbHandle.IsOpen())
   1.188 +		{
   1.189 +		iDbHandle.OpenL();
   1.190 +		}
   1.191 +
   1.192 +	if(!iFlurryQueue)
   1.193 +		{
   1.194 +		iFlurryQueue = CAuthoriserFifo::NewL();
   1.195 +		}
   1.196 +	if(!iFlurryQueueBeingProcessed)
   1.197 +		{
   1.198 +		iFlurryQueueBeingProcessed = CAuthoriserFifo::NewL();
   1.199 +		}
   1.200 +	}
   1.201 +
   1.202 +void CUpsServer::FreeUncompressableMemory()
   1.203 +/**
   1.204 +	Frees memory which can not be compressed down to a known level for OOM testing.
   1.205 + */
   1.206 +	{
   1.207 +	iDbHandle.Close();
   1.208 +	
   1.209 +	if(iPluginManager)
   1.210 +		{
   1.211 +		iPluginManager->Unload();
   1.212 +		delete iPluginManager;
   1.213 +		iPluginManager = 0;
   1.214 +		}
   1.215 +
   1.216 +	iPolicyCache.Release();
   1.217 +	}
   1.218 +
   1.219 +
   1.220 +CUpsServer::~CUpsServer()
   1.221 +/**
   1.222 +	Cleanup the server, in particular close the RFs session.
   1.223 + */
   1.224 +	{
   1.225 +	iDisputed.Close();
   1.226 +	
   1.227 +	(void) RProperty::Delete(KUpsServiceConfigProperty);
   1.228 +	
   1.229 +	delete iFlurryQueueBeingProcessed;
   1.230 +	iFlurryQueueBeingProcessed = 0;
   1.231 +
   1.232 +	delete iFlurryQueue;
   1.233 +	iFlurryQueue = 0;
   1.234 +
   1.235 +	FreeUncompressableMemory();
   1.236 +
   1.237 +	delete iSwiWatcher;
   1.238 +	iSwiWatcher = 0;
   1.239 +	iFs.Close();
   1.240 +	}
   1.241 +
   1.242 +CScsSession* CUpsServer::DoNewSessionL(const RMessage2& /*aMessage*/)
   1.243 +/**
   1.244 +	Implement CScsServer by allocating a new instance of CUpsSession.
   1.245 +
   1.246 +	@param	aMessage		Standard server-side handle to message.	 Not used.
   1.247 +	@return					New instance of CUpsSession which is owned by the
   1.248 +							caller.
   1.249 + */
   1.250 +	{
   1.251 +	return CUpsSession::NewL(*this);
   1.252 +	}
   1.253 +
   1.254 +
   1.255 +void CUpsServer::DoPreHeapMarkOrCheckL()
   1.256 +/**
   1.257 +	This function is called by the framework just before settingchecking a heap mark. We need to compress/free memory
   1.258 +	down to a state which should be the same both before and after the test operations.
   1.259 +*/
   1.260 +	{
   1.261 +#ifdef _DEBUG
   1.262 +	if(iAsyncRequests.Count() != 0)
   1.263 +		{
   1.264 +		User::Leave(KErrServerBusy);
   1.265 +		}
   1.266 +	iDisputed.Compress();
   1.267 +	iFlurryQueue->Compress();
   1.268 +	iFlurryQueueBeingProcessed->Compress();
   1.269 +	FreeUncompressableMemory();
   1.270 +#endif
   1.271 +	}
   1.272 +
   1.273 +void CUpsServer::DoPostHeapMarkOrCheckL()
   1.274 +/**
   1.275 +	Called immediately after setting/checking the heap mark and therefore just after DoPreHeapMarkOrCheckL.
   1.276 +	This function needs to re-allocate uncompressable data structures which were destroyed by DoPreHeapMarkOrCheckL.
   1.277 +*/
   1.278 +	{
   1.279 +#ifdef _DEBUG
   1.280 +	SetupL();
   1.281 +#endif
   1.282 +	}
   1.283 +
   1.284 +void CUpsServer::GateKeeperL(CAuthoriser *aAuthoriser)
   1.285 +	/**
   1.286 +	   If no dialog is in progress, the server will note one is in
   1.287 +	   progress, and tell the aAuthoriser it can continue (by calling
   1.288 +	   ClearedToDisplayL).
   1.289 +
   1.290 +	   Whenever a CAuthoriser finishes it MUST call our AuthoriserDone
   1.291 +	   function. This will allow us to cleanup our queues and clear
   1.292 +	   the next dialog to display.
   1.293 +
   1.294 +	   If a dialog is already in progress, the the aAuthoriser will be
   1.295 +	   added to iFlurryQueue for later processing.
   1.296 +
   1.297 +	   @param aAuthoriser to queue
   1.298 +	 */
   1.299 +	{
   1.300 +	if(iCurrentDialog)
   1.301 +		{
   1.302 +		// Add to queue of requests requiring re-processing later. This includes requests which want to display
   1.303 +		// a dialog and ones which matches a recordId which is under dispute (i.e. Where ForcePrompt has been
   1.304 +		// called and returned yes, but the prompt hasn't been displayed yet).
   1.305 +		iFlurryQueue->PushL(aAuthoriser);
   1.306 +		return;
   1.307 +		}
   1.308 +	iCurrentDialog = aAuthoriser;
   1.309 +	iCurrentDialog->ClearedToDisplayL();
   1.310 +	}
   1.311 +
   1.312 +void CUpsServer::AuthoriserDone(CAuthoriser *aAuthoriser)
   1.313 +/**
   1.314 +	See CUpsServer::AuthoriserDoneL for documentation.
   1.315 +*/
   1.316 +	{
   1.317 +	TRAP_IGNORE(AuthoriserDoneL(aAuthoriser));
   1.318 +	}
   1.319 +
   1.320 +void CUpsServer::AuthoriserDoneL(CAuthoriser *aAuthoriser)
   1.321 +	/**
   1.322 +	   The CAuthoriser has either completed the request, been
   1.323 +	   cancelled, or failed somehow.
   1.324 +
   1.325 +	   If it is in either FIFO it needs removing.
   1.326 +
   1.327 +	   If it is the current display dialog, then we need to check the
   1.328 +	   FIFOs, and maybe swap them, and call WakeupNextPending.
   1.329 +	*/
   1.330 +	{
   1.331 +	// Remove from lists.
   1.332 +	// Note the FIFO object does NOT leave if the object is not found.
   1.333 +	iFlurryQueue->RemoveL(aAuthoriser);
   1.334 +	iFlurryQueueBeingProcessed->RemoveL(aAuthoriser);
   1.335 +
   1.336 +	if(aAuthoriser == iCurrentDialog)
   1.337 +		{
   1.338 +		iCurrentDialog = 0;
   1.339 +
   1.340 +		if(iFlurryQueueBeingProcessed->IsEmpty())
   1.341 +			{
   1.342 +			// Swap queues
   1.343 +			CAuthoriserFifo *tmp = iFlurryQueue;
   1.344 +			iFlurryQueue = iFlurryQueueBeingProcessed;
   1.345 +			iFlurryQueueBeingProcessed = tmp;
   1.346 +			}
   1.347 +		WakeupNextPendingL();
   1.348 +		}
   1.349 +	}
   1.350 +
   1.351 +void CUpsServer::WakeupNextPendingL()
   1.352 +	/**
   1.353 +	   This function does the following:-
   1.354 +
   1.355 +	   1) If iFlurryQueueBeingProcessed is empty it returns.
   1.356 +	   
   1.357 +	   2) Removes the first authoriser from iFlurryQueueBeingProcessed
   1.358 +	   and calls SetPending to mark it as no longer pending.
   1.359 +	   
   1.360 +	   3) Increases its priority to EPriorityUserInput (this makes
   1.361 +	   sure it will be handled ahead of any incoming requests)
   1.362 +
   1.363 +	   4) Sets it active and completes it so it runs.
   1.364 +
   1.365 +	   It will run BEFORE any incoming requests.
   1.366 +	   
   1.367 +	   The first thing it must do is call this function again. This
   1.368 +	   ensures all pending requests are re-processed in order.
   1.369 +
   1.370 +	   Normally it will then re-lookup its fingerprints in the
   1.371 +	   database, if found it may complete client request. If it
   1.372 +	   decides it still needs to display a dialog it should call
   1.373 +	   GateKeeper again.
   1.374 +	 */
   1.375 +	{
   1.376 +	if(iFlurryQueueBeingProcessed->IsEmpty())
   1.377 +		{
   1.378 +		return;
   1.379 +		}
   1.380 +	
   1.381 +	CAuthoriser *authoriser = iFlurryQueueBeingProcessed->PopL();
   1.382 +	// Set priority of authoriser to EPriorityHigh-1. This is higher
   1.383 +	// than any incoming work, but lower than deferred deletes.
   1.384 +	authoriser->SetPriority(CActive::EPriorityHigh - 1);
   1.385 +	authoriser->Wakeup();
   1.386 +	}
   1.387 +
   1.388 +void CUpsServer::DisputeRecordIdL(TUint32 aRecordId)
   1.389 +/**
   1.390 +	Add the specified record to the list of disputed record IDs.
   1.391 +*/
   1.392 +	{
   1.393 +	DEBUG_PRINTF2(_L8("CUpsServer::DisputeRecordIdL(%d)\n"), aRecordId);
   1.394 +	User::LeaveIfError(iDisputed.InsertInOrder(aRecordId));
   1.395 +	}
   1.396 +
   1.397 +void CUpsServer::UnDisputeRecordIdL(TUint32 aRecordId)
   1.398 +/**
   1.399 +	Deletes the specified record from the list of disputed record IDs.
   1.400 +*/
   1.401 +	{
   1.402 +	DEBUG_PRINTF2(_L8("CUpsServer::UnDisputeRecordIdL(%d)\n"), aRecordId);
   1.403 +	TInt i = iDisputed.FindInOrderL(aRecordId);
   1.404 +	User::LeaveIfError(i);
   1.405 +	iDisputed.Remove(i);
   1.406 +	}
   1.407 +
   1.408 +TBool CUpsServer::IsRecordIdDisputed(TUint32 aRecordId) const
   1.409 +/**
   1.410 +	Checks if the specified record is under dispute. A record is disputed
   1.411 +	if the evaluator ForcePromptL call for a match on that record return ETrue to
   1.412 +	force a prompt to be displayed.
   1.413 +*/
   1.414 +	{
   1.415 +	TBool disputed = iDisputed.FindInOrder(aRecordId) >= 0;
   1.416 +	//RDebug::Printf("CUpsServer::IsRecordIdDisputed(%d) - returning %s\n", 
   1.417 +	//				aRecordId,
   1.418 +	//				(disputed)?("EFalse"):("EFalse"));
   1.419 +	return disputed;
   1.420 +	}
   1.421 +
   1.422 +//
   1.423 +// Implementation of CSwiWatcher
   1.424 +//
   1.425 +CSwiWatcher *CSwiWatcher::NewL(CUpsServer &aUpsServer)
   1.426 +	{
   1.427 +	CSwiWatcher *self = new(ELeave) CSwiWatcher(aUpsServer);
   1.428 +	CleanupStack::PushL(self);
   1.429 +	self->ConstructL();
   1.430 +	CleanupStack::Pop(self);
   1.431 +	return self;
   1.432 +	}
   1.433 +
   1.434 +CSwiWatcher::CSwiWatcher(CUpsServer &aUpsServer)
   1.435 +	: CActive(CActive::EPriorityHigh),
   1.436 +	  iUpsServer(aUpsServer)
   1.437 +	{
   1.438 +	CActiveScheduler::Add(this);
   1.439 +	}
   1.440 +
   1.441 +void CSwiWatcher::ConstructL()
   1.442 +/**
   1.443 +	Subscribe for notification for writes to the SWI P&S property.
   1.444 +	We do not check the actual value because it is not guaranteed that we will run for every change.
   1.445 +*/
   1.446 +	{
   1.447 +	User::LeaveIfError(iSwiProperty.Attach(KUidSystemCategory, KSAUidSoftwareInstallKeyValue));
   1.448 +	iSwiProperty.Subscribe(iStatus);
   1.449 +	SetActive();
   1.450 +	}
   1.451 +
   1.452 +void CSwiWatcher::RunL()
   1.453 +/**
   1.454 +	SWI has changed state, so unload any unused plugins.
   1.455 +	We do this for EVERY state change which we manage to run for, which is overkill, but the unload call
   1.456 +	is cheap/free if there are no plugins which require unloading.
   1.457 +*/
   1.458 +	{
   1.459 +	User::LeaveIfError(iStatus.Int());
   1.460 +	
   1.461 +	iSwiProperty.Subscribe(iStatus);
   1.462 +	SetActive();
   1.463 +
   1.464 +	// Tell the plugin manager to unload plugins which are NOT in use. 
   1.465 +	iUpsServer.iPluginManager->Unload();
   1.466 +	}
   1.467 +
   1.468 +void CSwiWatcher::DoCancel()
   1.469 +	{
   1.470 +	iSwiProperty.Cancel();
   1.471 +	}
   1.472 +
   1.473 +CSwiWatcher::~CSwiWatcher()
   1.474 +	{
   1.475 +	Cancel();
   1.476 +	iSwiProperty.Close();
   1.477 +	}
   1.478 +
   1.479 +
   1.480 +} // End of namespace UserPromptService
   1.481 +// End of file