os/security/authorisation/userpromptservice/server/source/upsserver/upsserver.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 * Implements CUpsServer.	See class and function definitions for
    16 * more information.
    17 *
    18 */
    19 
    20 
    21 /**
    22  @file
    23 */
    24 
    25 #include "upsserver.h"
    26 #include "policycache.h"
    27 #include "pluginmanager.h"
    28 #include <ups/upsdbw.h>
    29 #include <ups/cliententity.h>
    30 #include <ups/dialogcreator.h>
    31 #include <ups/fingerprint.h>
    32 #include <ups/policy.h>
    33 #include <ups/policyevaluator.h>
    34 #include <e32property.h>
    35 #include "authoriser.h"
    36 #include <sacls.h>
    37 #include "upsserver_p.h"
    38 
    39 namespace UserPromptService
    40 {
    41 
    42 static const TInt upsPolicyRangeCount = 8;
    43 static const TInt upsPolicyRanges[upsPolicyRangeCount] = 
    44 				{
    45 					0,
    46 					// Range 0 - 0 to EBaseSession-1
    47 					// Not used
    48 					CScsServer::EBaseSession,
    49 					// Range 1 - EBaseSession  to EBaseSession | EMngmntRead-1
    50 					//
    51 					// These codes used to create subsessions and to query the policy
    52 					// authorisation settings.
    53 					//
    54 					// (ESessSubsessFromThreadId/EGetClientConfigLength/EGetClientConfigData)
    55 					//
    56 					CScsServer::EBaseSession | EMngmntRead,
    57 					// Range 2 - EBaseSession | EMngmntRead to EBaseSession | EMngmntDelete - 1
    58 					//
    59 					// Management READ APIs
    60 					//
    61 					CScsServer::EBaseSession | EMngmntDelete,
    62 					// Range 3 - EBaseSession | EMngmntDelete to EBaseSession | EMngmntUpdate - 1
    63 					// Management DELETE API (ie. delete entire database or selected entries).
    64 					//
    65 					CScsServer::EBaseSession | EMngmntUpdate,
    66 					// Range 4 - EBaseSession | EMngmntUpdate to EBaseSession | ESwiObserver - 1
    67 					// Management  UPDATE API (ie. change an existing decision).
    68 					//
    69 					CScsServer::EBaseSession | ESwiObserver,
    70 					// Range 5 - EBaseSession | ESwiObserver to EBaseSubSession - 1
    71 					// SWI observer management API.
    72 					//
    73 					CScsServer::EBaseSubSession,
    74 					// Range 6 - EBaseSubSession to EBaseMustAllow-1
    75 					//
    76 					// System Server APIs
    77 					// Authorise - (ESubsessPreparePrompt/ESubsessExecutePrompt)
    78 					CScsServer::EBaseMustAllow	
    79 					// Range 7 - EBaseMustAllow to KMaxTInt inclusive
    80 					//
    81 					// SCS internal APIs to create subsessions, cancel requests etc.
    82 				};
    83 
    84 static const TUint8 upsPolicyElementsIndex[upsPolicyRangeCount] = 
    85 				{
    86 					CPolicyServer::ENotSupported, // Range 0 - Not used
    87 					CPolicyServer::EAlwaysPass, // Range 1 - Subsess and auth policy
    88 					0, // Range 2 - Management READ APIs
    89 					1, // Range 3 - Management DELETE APIs
    90 					2, // Range 4 - Management UPDATE APIs
    91 					3, // Range 5 - SWI observer APIs
    92 					4, // Range 6 - System Server APIs
    93 					CPolicyServer::EAlwaysPass // Range 7 - SCS internal
    94 				};
    95 
    96 // 0x102836C3 == Swi::KUidSwiObserver.iUid from swiobserver.h BUT we can not include that because SWI is optional
    97 // and we are not!
    98 static const TSecureId KSwiObserverSid(0x102836C3);
    99 static const CPolicyServer::TPolicyElement upsPolicyPolicyElements[5] = 
   100 {
   101 				{_INIT_SECURITY_POLICY_C1(ECapabilityReadDeviceData), CPolicyServer::EFailClient},	
   102 				{_INIT_SECURITY_POLICY_C1(ECapabilityWriteDeviceData), CPolicyServer::EFailClient},	
   103 				{_INIT_SECURITY_POLICY_C1(ECapabilityAllFiles), CPolicyServer::EFailClient},
   104 				{_INIT_SECURITY_POLICY_S0(KSwiObserverSid), CPolicyServer::EFailClient},
   105 				{_INIT_SECURITY_POLICY_C1(ECapabilityProtServ), CPolicyServer::EFailClient}
   106 };
   107 
   108 static const CPolicyServer::TPolicy upsPolicy =
   109 				{
   110 				CPolicyServer::EAlwaysPass, // Allow all connects
   111 				upsPolicyRangeCount,
   112 				upsPolicyRanges,
   113 				upsPolicyElementsIndex,
   114 				upsPolicyPolicyElements,
   115 				};
   116 
   117 _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
   118 _LIT_SECURITY_POLICY_C1(KAllowProtServ, ECapabilityProtServ); //< All our system server clients will have ProtServ, so limit reading of the (internal) flag to them.
   119 
   120 CUpsServer* CUpsServer::NewLC()
   121 /**
   122 	Factory function allocates new, initialized instance of
   123 	CUpsServer which is left on the cleanup stack.
   124 
   125 	@return					New, initialized instance of CUpsServer
   126 							which is left on the cleanup stack.
   127  */
   128 	{
   129 	CUpsServer* self = new(ELeave) CUpsServer();
   130 	CleanupStack::PushL(self);
   131 	self->ConstructL();
   132 	return self;
   133 	}
   134 
   135 CUpsServer::CUpsServer()
   136 /**
   137 	Initializes the superclass with this server's version.
   138  */
   139 	:	CScsServer(UserPromptService::Version(), upsPolicy),
   140 		iPolicyCache(iFs),
   141 		iDbHandle(iFs)
   142 	{
   143 	// empty.
   144 	}
   145 
   146 void CUpsServer::ConstructL()
   147 /**
   148 	Second-phase construction initializes the superclass and
   149 	starts the server.
   150  */
   151 	{
   152 	CScsServer::ConstructL(UserPromptService::KShutdownPeriodUs);
   153 	User::LeaveIfError(iFs.Connect());
   154 
   155 	TInt r = RProperty::Define(KUpsServiceConfigProperty, RProperty::EInt, KAllowProtServ, KAllowUpsServer);
   156 	if(r != KErrAlreadyExists)
   157 		{
   158 		User::LeaveIfError(r);
   159 		}
   160 
   161 	iSwiWatcher = CSwiWatcher::NewL(*this);
   162 
   163 	SetupL();
   164 
   165 	StartL(UserPromptService::KUpsServerName);
   166 	}
   167 
   168 void CUpsServer::SetupL()
   169 /**
   170 	Setup memory variables which are not already setup.
   171 	Used during intial construction and after a call to FreeUncompressableMemory.
   172  */
   173 	{
   174 	if(!iPolicyCache.IsOpen())
   175 		{
   176 		iPolicyCache.OpenL();
   177 		}
   178 	if(!iPluginManager)
   179 		{
   180 		iPluginManager = CPluginManager::NewL();
   181 		}
   182 
   183 	// Create/Open the database
   184 	if(!iDbHandle.IsOpen())
   185 		{
   186 		iDbHandle.OpenL();
   187 		}
   188 
   189 	if(!iFlurryQueue)
   190 		{
   191 		iFlurryQueue = CAuthoriserFifo::NewL();
   192 		}
   193 	if(!iFlurryQueueBeingProcessed)
   194 		{
   195 		iFlurryQueueBeingProcessed = CAuthoriserFifo::NewL();
   196 		}
   197 	}
   198 
   199 void CUpsServer::FreeUncompressableMemory()
   200 /**
   201 	Frees memory which can not be compressed down to a known level for OOM testing.
   202  */
   203 	{
   204 	iDbHandle.Close();
   205 	
   206 	if(iPluginManager)
   207 		{
   208 		iPluginManager->Unload();
   209 		delete iPluginManager;
   210 		iPluginManager = 0;
   211 		}
   212 
   213 	iPolicyCache.Release();
   214 	}
   215 
   216 
   217 CUpsServer::~CUpsServer()
   218 /**
   219 	Cleanup the server, in particular close the RFs session.
   220  */
   221 	{
   222 	iDisputed.Close();
   223 	
   224 	(void) RProperty::Delete(KUpsServiceConfigProperty);
   225 	
   226 	delete iFlurryQueueBeingProcessed;
   227 	iFlurryQueueBeingProcessed = 0;
   228 
   229 	delete iFlurryQueue;
   230 	iFlurryQueue = 0;
   231 
   232 	FreeUncompressableMemory();
   233 
   234 	delete iSwiWatcher;
   235 	iSwiWatcher = 0;
   236 	iFs.Close();
   237 	}
   238 
   239 CScsSession* CUpsServer::DoNewSessionL(const RMessage2& /*aMessage*/)
   240 /**
   241 	Implement CScsServer by allocating a new instance of CUpsSession.
   242 
   243 	@param	aMessage		Standard server-side handle to message.	 Not used.
   244 	@return					New instance of CUpsSession which is owned by the
   245 							caller.
   246  */
   247 	{
   248 	return CUpsSession::NewL(*this);
   249 	}
   250 
   251 
   252 void CUpsServer::DoPreHeapMarkOrCheckL()
   253 /**
   254 	This function is called by the framework just before settingchecking a heap mark. We need to compress/free memory
   255 	down to a state which should be the same both before and after the test operations.
   256 */
   257 	{
   258 #ifdef _DEBUG
   259 	if(iAsyncRequests.Count() != 0)
   260 		{
   261 		User::Leave(KErrServerBusy);
   262 		}
   263 	iDisputed.Compress();
   264 	iFlurryQueue->Compress();
   265 	iFlurryQueueBeingProcessed->Compress();
   266 	FreeUncompressableMemory();
   267 #endif
   268 	}
   269 
   270 void CUpsServer::DoPostHeapMarkOrCheckL()
   271 /**
   272 	Called immediately after setting/checking the heap mark and therefore just after DoPreHeapMarkOrCheckL.
   273 	This function needs to re-allocate uncompressable data structures which were destroyed by DoPreHeapMarkOrCheckL.
   274 */
   275 	{
   276 #ifdef _DEBUG
   277 	SetupL();
   278 #endif
   279 	}
   280 
   281 void CUpsServer::GateKeeperL(CAuthoriser *aAuthoriser)
   282 	/**
   283 	   If no dialog is in progress, the server will note one is in
   284 	   progress, and tell the aAuthoriser it can continue (by calling
   285 	   ClearedToDisplayL).
   286 
   287 	   Whenever a CAuthoriser finishes it MUST call our AuthoriserDone
   288 	   function. This will allow us to cleanup our queues and clear
   289 	   the next dialog to display.
   290 
   291 	   If a dialog is already in progress, the the aAuthoriser will be
   292 	   added to iFlurryQueue for later processing.
   293 
   294 	   @param aAuthoriser to queue
   295 	 */
   296 	{
   297 	if(iCurrentDialog)
   298 		{
   299 		// Add to queue of requests requiring re-processing later. This includes requests which want to display
   300 		// a dialog and ones which matches a recordId which is under dispute (i.e. Where ForcePrompt has been
   301 		// called and returned yes, but the prompt hasn't been displayed yet).
   302 		iFlurryQueue->PushL(aAuthoriser);
   303 		return;
   304 		}
   305 	iCurrentDialog = aAuthoriser;
   306 	iCurrentDialog->ClearedToDisplayL();
   307 	}
   308 
   309 void CUpsServer::AuthoriserDone(CAuthoriser *aAuthoriser)
   310 /**
   311 	See CUpsServer::AuthoriserDoneL for documentation.
   312 */
   313 	{
   314 	TRAP_IGNORE(AuthoriserDoneL(aAuthoriser));
   315 	}
   316 
   317 void CUpsServer::AuthoriserDoneL(CAuthoriser *aAuthoriser)
   318 	/**
   319 	   The CAuthoriser has either completed the request, been
   320 	   cancelled, or failed somehow.
   321 
   322 	   If it is in either FIFO it needs removing.
   323 
   324 	   If it is the current display dialog, then we need to check the
   325 	   FIFOs, and maybe swap them, and call WakeupNextPending.
   326 	*/
   327 	{
   328 	// Remove from lists.
   329 	// Note the FIFO object does NOT leave if the object is not found.
   330 	iFlurryQueue->RemoveL(aAuthoriser);
   331 	iFlurryQueueBeingProcessed->RemoveL(aAuthoriser);
   332 
   333 	if(aAuthoriser == iCurrentDialog)
   334 		{
   335 		iCurrentDialog = 0;
   336 
   337 		if(iFlurryQueueBeingProcessed->IsEmpty())
   338 			{
   339 			// Swap queues
   340 			CAuthoriserFifo *tmp = iFlurryQueue;
   341 			iFlurryQueue = iFlurryQueueBeingProcessed;
   342 			iFlurryQueueBeingProcessed = tmp;
   343 			}
   344 		WakeupNextPendingL();
   345 		}
   346 	}
   347 
   348 void CUpsServer::WakeupNextPendingL()
   349 	/**
   350 	   This function does the following:-
   351 
   352 	   1) If iFlurryQueueBeingProcessed is empty it returns.
   353 	   
   354 	   2) Removes the first authoriser from iFlurryQueueBeingProcessed
   355 	   and calls SetPending to mark it as no longer pending.
   356 	   
   357 	   3) Increases its priority to EPriorityUserInput (this makes
   358 	   sure it will be handled ahead of any incoming requests)
   359 
   360 	   4) Sets it active and completes it so it runs.
   361 
   362 	   It will run BEFORE any incoming requests.
   363 	   
   364 	   The first thing it must do is call this function again. This
   365 	   ensures all pending requests are re-processed in order.
   366 
   367 	   Normally it will then re-lookup its fingerprints in the
   368 	   database, if found it may complete client request. If it
   369 	   decides it still needs to display a dialog it should call
   370 	   GateKeeper again.
   371 	 */
   372 	{
   373 	if(iFlurryQueueBeingProcessed->IsEmpty())
   374 		{
   375 		return;
   376 		}
   377 	
   378 	CAuthoriser *authoriser = iFlurryQueueBeingProcessed->PopL();
   379 	// Set priority of authoriser to EPriorityHigh-1. This is higher
   380 	// than any incoming work, but lower than deferred deletes.
   381 	authoriser->SetPriority(CActive::EPriorityHigh - 1);
   382 	authoriser->Wakeup();
   383 	}
   384 
   385 void CUpsServer::DisputeRecordIdL(TUint32 aRecordId)
   386 /**
   387 	Add the specified record to the list of disputed record IDs.
   388 */
   389 	{
   390 	DEBUG_PRINTF2(_L8("CUpsServer::DisputeRecordIdL(%d)\n"), aRecordId);
   391 	User::LeaveIfError(iDisputed.InsertInOrder(aRecordId));
   392 	}
   393 
   394 void CUpsServer::UnDisputeRecordIdL(TUint32 aRecordId)
   395 /**
   396 	Deletes the specified record from the list of disputed record IDs.
   397 */
   398 	{
   399 	DEBUG_PRINTF2(_L8("CUpsServer::UnDisputeRecordIdL(%d)\n"), aRecordId);
   400 	TInt i = iDisputed.FindInOrderL(aRecordId);
   401 	User::LeaveIfError(i);
   402 	iDisputed.Remove(i);
   403 	}
   404 
   405 TBool CUpsServer::IsRecordIdDisputed(TUint32 aRecordId) const
   406 /**
   407 	Checks if the specified record is under dispute. A record is disputed
   408 	if the evaluator ForcePromptL call for a match on that record return ETrue to
   409 	force a prompt to be displayed.
   410 */
   411 	{
   412 	TBool disputed = iDisputed.FindInOrder(aRecordId) >= 0;
   413 	//RDebug::Printf("CUpsServer::IsRecordIdDisputed(%d) - returning %s\n", 
   414 	//				aRecordId,
   415 	//				(disputed)?("EFalse"):("EFalse"));
   416 	return disputed;
   417 	}
   418 
   419 //
   420 // Implementation of CSwiWatcher
   421 //
   422 CSwiWatcher *CSwiWatcher::NewL(CUpsServer &aUpsServer)
   423 	{
   424 	CSwiWatcher *self = new(ELeave) CSwiWatcher(aUpsServer);
   425 	CleanupStack::PushL(self);
   426 	self->ConstructL();
   427 	CleanupStack::Pop(self);
   428 	return self;
   429 	}
   430 
   431 CSwiWatcher::CSwiWatcher(CUpsServer &aUpsServer)
   432 	: CActive(CActive::EPriorityHigh),
   433 	  iUpsServer(aUpsServer)
   434 	{
   435 	CActiveScheduler::Add(this);
   436 	}
   437 
   438 void CSwiWatcher::ConstructL()
   439 /**
   440 	Subscribe for notification for writes to the SWI P&S property.
   441 	We do not check the actual value because it is not guaranteed that we will run for every change.
   442 */
   443 	{
   444 	User::LeaveIfError(iSwiProperty.Attach(KUidSystemCategory, KSAUidSoftwareInstallKeyValue));
   445 	iSwiProperty.Subscribe(iStatus);
   446 	SetActive();
   447 	}
   448 
   449 void CSwiWatcher::RunL()
   450 /**
   451 	SWI has changed state, so unload any unused plugins.
   452 	We do this for EVERY state change which we manage to run for, which is overkill, but the unload call
   453 	is cheap/free if there are no plugins which require unloading.
   454 */
   455 	{
   456 	User::LeaveIfError(iStatus.Int());
   457 	
   458 	iSwiProperty.Subscribe(iStatus);
   459 	SetActive();
   460 
   461 	// Tell the plugin manager to unload plugins which are NOT in use. 
   462 	iUpsServer.iPluginManager->Unload();
   463 	}
   464 
   465 void CSwiWatcher::DoCancel()
   466 	{
   467 	iSwiProperty.Cancel();
   468 	}
   469 
   470 CSwiWatcher::~CSwiWatcher()
   471 	{
   472 	Cancel();
   473 	iSwiProperty.Close();
   474 	}
   475 
   476 
   477 } // End of namespace UserPromptService
   478 // End of file