os/security/authorisation/userpromptservice/server/source/upsserver/authoriser.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-2009 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 CAuthoriser.	 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 "authoriser.h"
    28 #include <ups/upsdbw.h>
    29 #include "upslog.h"
    30 #include <ups/dialogcreator.h>
    31 #include <ups/policyevaluator.h>
    32 
    33 namespace UserPromptService
    34 {
    35 
    36 CAuthoriser* CAuthoriser::NewL(RPolicyCacheCountedHandle &aPolicyCache,
    37 								   CUpsSession* aSession, CUpsSubsession* aSubsession, TBool aServerCheckOk,
    38 								   TThreadId &aClientTid, TProcessId &aClientPId,
    39 								   const RMessage2& aMessage, const TServiceId& aServiceId,
    40 								   RBuf &aDestination, RBuf8 &aOpaqueData)
    41 	/**
    42 	   Factory function allocates a new, initialized instance of CAuthoriser,
    43 	   registered for the supplied session and subsession.
    44 	   
    45 	   If construction is successful, the caller should pass ownership to
    46 	   the SCS framework (TransferToScsFrameworkL), and pop the
    47 	   CAuthoriser from the cleanupstack. From this point onwards the
    48 	   request should be completed by the CAuthoriser/CAsyncRequst code,
    49 	   so the caller must not return or leave with any code except
    50 	   KErrScsSetupAsync. This is why the StartProcessingRequest function
    51 	   is defined as non-leaving.
    52 
    53 	   @param	aPolicyCache	The server policy cache manager.
    54 	   @param	aSession		Session on which this request was launched.
    55 	   @param	aSubsession		Subsession on which this request was launched.
    56 	   @param	aServerCheckOk	Did the system server checks pass?
    57 	   @param	aClientThread	Handle to the user client thread.
    58 	   @param	aMessage		Standard server-side handle to message.
    59 	   @param	aDestination	We take ownership of the RBuf and close the callers handle
    60 	   @param	aOpaqueData		We take ownership of the RBuf and close the callers handle
    61 	   @return					New, initialized instance of CAuthoriser, which
    62 	   is owned by the server's collection of outstanding
    63 	   requests.
    64 	*/
    65 	{
    66 	CAuthoriser* self = new(ELeave) CAuthoriser(aPolicyCache, aSession, aSubsession, aMessage);
    67 	CleanupStack::PushL(self);
    68 	self->ConstructL(aServerCheckOk, aClientTid, aClientPId, aServiceId, aDestination, aOpaqueData);
    69 	CleanupStack::Pop(self);
    70 	return self;
    71 	}
    72 
    73 CAuthoriser::CAuthoriser(RPolicyCacheCountedHandle &aPolicyCache,
    74 						   CUpsSession* aSession, CUpsSubsession* aSubsession,
    75 						   const RMessage2& aMessage)
    76 	/**
    77 	   This private constructor initializes the superclass and prevents direct instantiation.
    78 
    79 	   @param	aPolicyCache		The server policy cache manager.
    80 	   @param	aSession			Session on which this request was launched.
    81 	   @param	aSubsession		Subsession on which this request was launched.
    82 	   @param	aMessage		Standard server-side handle to message.
    83 	   @param	aDestination	HBufC description, takes ownership.
    84 	   @param	aOpaqueData		0 or HBufC opaqueData, takes ownership.
    85 	*/
    86 	:	CAsyncRequest(aSession, aSubsession, aMessage),
    87 		iPolicyCache(aPolicyCache)
    88 	{
    89 	// empty.
    90 	}
    91 
    92 void CAuthoriser::ConstructL(TBool aServerCheckOk, TThreadId &aClientTid, TProcessId &aClientPid, const TServiceId& aServiceId, RBuf &aDestination, RBuf8 &aOpaqueData)
    93 	/**
    94 	   Second-phase constructor allocates the timer which is used to generate
    95 	   a delay, and adds this object to the server's collection of outstanding
    96 	   requests.
    97 	*/
    98 	{
    99 	iState = ECheckPolicy;
   100 
   101 	RProcess clientProcess;
   102 	TInt r = clientProcess.Open(aClientPid);
   103 	if(r != KErrNone)
   104 		{
   105 		User::Leave(KErrUpsBadClientProcessId);
   106 		}
   107 	CleanupClosePushL(clientProcess);
   108 	
   109 	// Create a CPromptReqest for the policy lookup
   110 	iPromptRequest = CPromptRequest::NewL(clientProcess.SecureId(), // Client details
   111 										  clientProcess.VendorId(),
   112 										  aClientTid,
   113 										  aClientPid,
   114 										  iMessagePtr2.SecureId(), // Server SID
   115 										  aServiceId, // Server service ID
   116 										  aDestination, // Request detail, takes ownership
   117 										  aOpaqueData,	//				   takes ownership
   118 										  aServerCheckOk); 
   119 	
   120 	CleanupStack::PopAndDestroy(&clientProcess);
   121 	}
   122 
   123 void CAuthoriser::ProcessEventL(TAuthoriserEvent aEvent)
   124 	{
   125 	//	DEBUG_PRINTF4(_L8("0x%x CAuthoriser::ProcessEventL state %d, event %d\n"), this, iState, aEvent);
   126 	_LIT(KServerPanicState, "UPS-ProcessEventL");
   127 	switch(iState)
   128 		{
   129 		case ECheckPolicy:
   130 			CheckPolicyStateL(aEvent);
   131 			return;
   132 		case ECreatingFingerprints:
   133 			CreatingFingerprintsStateL(aEvent);
   134 			return;
   135 		case ECheckDatabase:
   136 			CheckDatabaseStateL(aEvent);
   137 			return;
   138 		case EPreparingDialog:
   139 			PreparingDialogStateL(aEvent);
   140 			return;
   141 		case EExecutingDialog:
   142 			ExecutingDialogStateL(aEvent);
   143 			return;
   144 BULLSEYE_OFF
   145 		}
   146 	
   147 	// Should not get here
   148 	User::Panic(KServerPanicState, iState);
   149 BULLSEYE_RESTORE
   150 	}
   151 
   152 
   153 void CAuthoriser::CheckPolicyStateL(TAuthoriserEvent aEvent)
   154 	{
   155 	switch(aEvent)
   156 		{
   157 		case EInternalRequestComplete:
   158 			// Caused by the ups sub session code calling Wakeup
   159 			// to start the request processing. We are now within the
   160 			// active scheduler error handling framework.
   161 
   162 			// This call will lookup the policy and move to the next
   163 			// state, or leave.
   164 			LookupPolicyL();
   165 			break;
   166 
   167 			BULLSEYE_OFF
   168 		case EClearedToDisplayDialog:
   169 			ASSERT(EFalse);
   170 			break;
   171 			BULLSEYE_RESTORE
   172 
   173 		case ECancel:
   174 			// This WILL happen if am authorise request is made and immediately cancelled (before CAuthoriser::Runl has
   175 			// the chance to run). We should complete our "fake" internal request so we do not block
   176 			// when we return to the DoCancel/CActive::Cancel which caused this event.
   177 			CompleteSelf();
   178 			break;
   179 BULLSEYE_OFF
   180 		}
   181 BULLSEYE_RESTORE
   182 	}
   183 
   184 void CAuthoriser::CreatingFingerprintsStateL(TAuthoriserEvent aEvent)
   185 	{
   186 	switch(aEvent)
   187 		{
   188 		case EInternalRequestComplete:
   189 			// This will move to the next state and lookup the fingerprints, or leave.
   190 			LookupFingerprintsL();
   191 			break;
   192 
   193 			BULLSEYE_OFF
   194 		case EClearedToDisplayDialog:
   195 			ASSERT(EFalse);
   196 			break;
   197 			BULLSEYE_RESTORE
   198 
   199 		case ECancel:
   200 			// Cancel the request to create the fingerprints
   201 			iPolicyEvaluator->Imp().Cancel();
   202 			break;
   203 BULLSEYE_OFF
   204 		}
   205 BULLSEYE_RESTORE
   206 	}
   207 
   208 void CAuthoriser::CheckDatabaseStateL(TAuthoriserEvent aEvent)
   209 	{
   210 	switch(aEvent)
   211 		{
   212 		case EInternalRequestComplete:
   213 			// Normally the create fingerprints state code will call
   214 			// LookupFingerprintsL to move to this state and do the
   215 			// lookup, but if we need to re-lookup the fingerprints a
   216 			// "fake" request will be issued and this code will be
   217 			// used.
   218 			LookupFingerprintsL();
   219 			break;
   220 		case EClearedToDisplayDialog:
   221 			// Change state and ask the dialog creator to start creating
   222 			// the dialog, or leave.
   223 			PrepareDialogL();
   224 			break;
   225 		case ECancel:
   226 			// Complete the fake request which was issued to try and
   227 			// get us to redo the fingerprint lookup.
   228 			CompleteSelf();
   229 			break;
   230 BULLSEYE_OFF
   231 		}
   232 BULLSEYE_RESTORE
   233 	}
   234 
   235 void CAuthoriser::PreparingDialogStateL(TAuthoriserEvent aEvent)
   236 	{
   237 	switch(aEvent)
   238 		{
   239 		case EInternalRequestComplete:
   240 			// Created dialog, now change state to execute and display
   241 			// it.
   242 			ExecuteDialogL();
   243 			break;
   244 
   245 			BULLSEYE_OFF
   246 		case EClearedToDisplayDialog:
   247 			ASSERT(EFalse);
   248 			break;
   249 			BULLSEYE_RESTORE
   250 
   251 		case ECancel:
   252 			// Cancel the request to create the dialog
   253 			iDialogCreator->Imp().Cancel();
   254 			break;
   255 BULLSEYE_OFF
   256 		}
   257 BULLSEYE_RESTORE
   258 	}
   259 
   260 void CAuthoriser::ExecutingDialogStateL(TAuthoriserEvent aEvent)
   261 	{
   262 	switch(aEvent)
   263 		{
   264 		case EInternalRequestComplete:
   265 			// Dialog complete, process the result and complete the
   266 			// client request.
   267 			ProcessDialogResultL();
   268 			break;
   269 
   270 			BULLSEYE_OFF
   271 		case EClearedToDisplayDialog:
   272 			ASSERT(EFalse);
   273 			break;
   274 			BULLSEYE_RESTORE
   275 
   276 		case ECancel:
   277 			// Cancel the request to execute the dialog
   278 			iDialogCreator->Imp().Cancel();
   279 			break;
   280 BULLSEYE_OFF
   281 		}
   282 BULLSEYE_RESTORE
   283 	}
   284 
   285 void CAuthoriser::Wakeup()
   286 	/**
   287 	   Raise and complete a request against self. Will cause RunL to
   288 	   be run within the active scheduler.
   289 	*/
   290 	{
   291 	iStatus = KRequestPending;
   292 	SetActive();
   293 	CompleteSelf();
   294 	}
   295 
   296 void CAuthoriser::CompleteSelf()
   297 	{
   298 	_LIT(KServerPanicState, "UPS-CompleteSelf");
   299 	switch(iState)
   300 		{
   301 		case ECheckPolicy:
   302 		case ECheckDatabase:
   303 			break;
   304 
   305 	BULLSEYE_OFF
   306 		case ECreatingFingerprints:
   307 		case EPreparingDialog:
   308 		case EExecutingDialog:
   309 			User::Panic(KServerPanicState, iState);
   310 			/*lint -unreachable */
   311 			return; // Not legal in these states
   312 		}
   313 	BULLSEYE_RESTORE
   314 		
   315 	if(iStatus == KRequestPending)
   316 		{
   317 		TRequestStatus *status = &iStatus;
   318 		User::RequestComplete(status, KErrNone);
   319 		}
   320 	}
   321 
   322 
   323 
   324 void CAuthoriser::ClearedToDisplayL()
   325 	/**
   326 	   The UPS server GateKeeper has granted us permission to proceed
   327 	   with dialog generation and display.
   328 	*/
   329 	{
   330 	ProcessEventL(EClearedToDisplayDialog);
   331 	}
   332 
   333 
   334 
   335 
   336 
   337 
   338 CAuthoriser::~CAuthoriser()
   339 	/**
   340 	   Close the timer which was initialized in ConstructL.
   341 	*/
   342 	{
   343 	iDialogFingerprint = 0; // MUST not delete, owned by CDialogCreator
   344 	
   345 	delete iDialogCreator;
   346 	iDialogCreator = 0;
   347 	
   348 	iDialogCreatorParams = 0; // MUST not delete, owned by evaluator
   349 	
   350 	iClientEntity = 0;	// MUST not delete, owned by evaluator
   351 	
   352 	iFingerprints.ResetAndDestroy();
   353 	
   354 	delete iPolicyEvaluator;
   355 	iPolicyEvaluator = 0;	
   356 
   357 	iPolicyCache.Release();
   358 	iPolicy = 0; // MUST not delete, ownded by policy cache
   359 	
   360 	delete iPromptRequest;
   361 	iPromptRequest = 0;
   362 	}
   363 
   364 void CAuthoriser::RunL()
   365 	{
   366 	// Wake up the next pending request now (if any), to make sure it
   367 	// will be processed ahead of any incoming requests.
   368 	UpsServer()->WakeupNextPendingL();
   369 	
   370 	// Reset our priority to standard
   371 	if(Priority() != CActive::EPriorityStandard)
   372 		{
   373 		SetPriority(CActive::EPriorityStandard);
   374 		}
   375 	User::LeaveIfError(iStatus.Int());
   376 	
   377 	ProcessEventL(EInternalRequestComplete);
   378 	}
   379 
   380 
   381 void CAuthoriser::DoCleanup()
   382 	{
   383 	if(iPromptForced)
   384 		{
   385 		// Have previously called ForcePromptL on a database record and it told us to 
   386 		// prompt,  so have previously marked the record as disputed.
   387 		TRAP_IGNORE(UpsServer()->UnDisputeRecordIdL(iPromptForcedRecordId));
   388 		iPromptForced = EFalse;
   389 		}
   390 
   391 	// Cancel current internal operation
   392 	Cancel();
   393 	
   394 	// Let the server know we are done
   395 	UpsServer()->AuthoriserDone(this);
   396 
   397 	// The framework will complete the client request and schedule us
   398 	// for deletion.
   399 	}
   400 
   401 
   402 
   403 
   404 void CAuthoriser::DoCancel()
   405 	/**
   406 	   Cancel the current operation.  This does not complete the client
   407 	   request or mark this object for deletion.
   408 	*/
   409 	{
   410 	TRAP_IGNORE(
   411 		// Wake up the next pending request now (if any), to make sure it
   412 		// will be processed ahead of any incoming requests.
   413 		UpsServer()->WakeupNextPendingL();
   414 		ProcessEventL(ECancel);
   415 		);
   416 	}
   417 
   418 void CAuthoriser::LookupPolicyL()
   419 	{
   420 	// This returns a ptr into the cache, so we have to be careful not to use it after the cache is deleted.
   421 	// This is why we wrap the cache in a RPolicyCacheCountedHandle.
   422 	iPolicy = iPolicyCache->MatchL(*iPromptRequest);
   423 	
   424 	ASSERT(iPolicy);
   425 	
   426 	if(iPolicy->PromptRequired())
   427 		{
   428 		// Policy contains both yes and no responses...
   429 		// Start creating the fingerprints
   430 		CreateFingerprintsL();
   431 		return;
   432 		}
   433 	
   434 	// Return result to system server
   435 	TUpsDecisionPckgBuf decisionBuf;
   436 	decisionBuf() = MapCPolicyTOptions2TUpsDecision(iPolicy->Options());
   437 	iMessagePtr2.WriteL(0, decisionBuf);
   438 	
   439 	CompleteAndMarkForDeletion(KErrNone);
   440 	}
   441 
   442 
   443 void CAuthoriser::CreateFingerprintsL()
   444 	/**
   445 	   Load Policy Evaluator and tell it to start generating the fingerprints
   446 	*/
   447 	{
   448 	iState = ECreatingFingerprints;
   449 
   450 	iPolicyEvaluator = UpsServer()->iPluginManager->CreateEvaluatorL(iPolicy->PolicyEvaluator());
   451 	
   452 	iPolicyEvaluator->Imp().GenerateFingerprints(*iPromptRequest, *iPolicy, 
   453 												 iFingerprints, iClientEntity, iDialogCreatorParams, iStatus);
   454 	
   455 	SetActive();
   456 	}
   457 
   458 _LIT8(KDefaultFingerprint,"*");
   459 //_LIT(KServerPanicDb, "UPS-BadDB");
   460 static const char * const KCorruptDb = "UPS-BadDB error=%d line=%d\n";
   461 
   462 void CAuthoriser::LookupFingerprintsL()
   463 	{
   464 	// Lookup in DB
   465 	iState = ECheckDatabase;
   466 
   467 	TPtrC8 clientEntityName(KNullDesC8());
   468 	if(iClientEntity)
   469 		{
   470 		clientEntityName.Set(iClientEntity->Name());
   471 		}
   472 	
   473 	CDecisionFilter *filter = CDecisionFilter::NewLC(iPromptRequest->ClientSid(),
   474 													 iPolicy->PolicyEvaluator(),
   475 													 iPromptRequest->ServiceId(),
   476 													 iPromptRequest->ServerSid(),
   477 													 KDefaultFingerprint(),
   478 													 clientEntityName,
   479 													 iPolicy->MajorVersion());
   480 	//
   481 	// Lookup the fingerprints in the DB and return the first match
   482 	//
   483 	CDecisionRecord *record = 0;
   484 	TInt fingerprintCount = iFingerprints.Count();
   485 	for(TInt i=0; i<fingerprintCount; ++i)
   486 		{
   487 		filter->SetFingerprintL(iFingerprints[i]->Fingerprint(), EEqual);
   488 		record = 0;
   489 		TRAPD(err, record = UpsServer()->iDbHandle->GetDecisionL(*filter));
   490 		if(err != KErrNone)
   491 			{
   492 			HandleDbErrorL(err);
   493 			}
   494 		
   495 		if(record)
   496 			{
   497 			break;
   498 			}
   499 		}
   500 	
   501 	if(record)
   502 		{
   503 		// Found record
   504 		CleanupStack::PushL(record);
   505 		// Read current eval info value from record.
   506 		iDialogEvaluatorInfo = record->iEvaluatorInfo;
   507 
   508 		if(UpsServer()->IsRecordIdDisputed(record->iRecordId))
   509 			{
   510 			// Matching record is under dispute so a dialog must be in progress.
   511 			// Queue for later re-evaluation.
   512 			UpsServer()->GateKeeperL(this);
   513 			return;
   514 			}
   515 
   516 		if(iPromptForced && (record->iRecordId != iPromptForcedRecordId))
   517 			{
   518 			// Have previously called ForcePromptL on a database record and it told us to 
   519 			// prompt, BUT we have now matched a different record ID! Presumably
   520 			// someone else overwrote or deleted our record....
   521 			//
   522 			// We need to undispute the old record id and continue as if ForcePromptL had
   523 			// never been called/returned yes. 
   524 			iPromptForced = EFalse;
   525 			UpsServer()->UnDisputeRecordIdL(iPromptForcedRecordId);
   526 			}
   527 		
   528 		// Call ForcePrompt to see if we need to prompt anyway
   529 		TUint newDialogEvaluatorInfo = iDialogEvaluatorInfo;
   530 		TBool forcePrompt = iPolicyEvaluator->Imp().ForcePromptL(*record, newDialogEvaluatorInfo);
   531 		if(forcePrompt)
   532 			{
   533 			iPromptForced = ETrue;
   534 			iPromptForcedRecordId = record->iRecordId;
   535 			UpsServer()->DisputeRecordIdL(iPromptForcedRecordId);
   536 			}
   537 		
   538 		if(newDialogEvaluatorInfo != iDialogEvaluatorInfo)
   539 			{
   540 			// Eavluator info changes, update our member variable copy
   541 			// so it is used in the dialog
   542 			iDialogEvaluatorInfo = newDialogEvaluatorInfo;
   543 			// If we ARE displaying a prompt, then when it completes,
   544 			// we will delete the existing record. If the user choice
   545 			// requires a new record we will use the evaluator value
   546 			// from our member variable
   547 			if(!forcePrompt)
   548 				{
   549 				// Not forcing a prompt, so update the DB now.
   550 				record->iEvaluatorInfo = newDialogEvaluatorInfo;
   551 				// If the update fails, we carry on anyway...
   552 				TRAPD(err, UpsServer()->iDbHandle->UpdateDecisionL(*filter, *record));
   553 				if(err != KErrNone)
   554 					{
   555 					HandleDbErrorL(err);
   556 					}				
   557 				}
   558 			}
   559 		
   560 		if(!forcePrompt)
   561 			{
   562 			// Return the result found in the DB to the system server
   563 			TUpsDecisionPckgBuf decisionBuf;
   564 			decisionBuf() = MapCPolicyTOptions2TUpsDecision((record->iResult) ? (CPolicy::EAlways) : (CPolicy::ENever));
   565 			iMessagePtr2.WriteL(0, decisionBuf);
   566 			
   567 			CleanupStack::PopAndDestroy(record);
   568 			CleanupStack::PopAndDestroy(filter);
   569 			CompleteAndMarkForDeletion(KErrNone);
   570 			return;
   571 			}
   572 		
   573 		// Prompt is being forced, so fall through
   574 		CleanupStack::PopAndDestroy(record);
   575 		}
   576 	
   577 	// Record not found, or prompt forced
   578 	CleanupStack::PopAndDestroy(filter);
   579 	
   580 	// Queue for clearence to display a dialog
   581 	UpsServer()->GateKeeperL(this);
   582 	}
   583 
   584 void CAuthoriser::PrepareDialogL()
   585 	{
   586 	iState = EPreparingDialog;
   587 	
   588 	iDialogCreator = UpsServer()->iPluginManager->CreateDialogCreatorL(iPolicy->DialogCreator());
   589 	
   590 	iDialogCreator->Imp().PrepareDialog(*iPromptRequest, *iPolicy, iFingerprints, 
   591 										iClientEntity, iDialogCreatorParams, iStatus);
   592 	SetActive();
   593 	}
   594 
   595 
   596 
   597 
   598 void CAuthoriser::ExecuteDialogL()
   599 	{
   600 	iState = EExecutingDialog;
   601 	iDialogCreator->Imp().DisplayDialog(iDialogSelectedOption, iDialogFingerprint, iDialogEvaluatorInfo, iStatus);
   602 	SetActive();
   603 	}
   604 
   605 void CAuthoriser::ProcessDialogResultL()
   606 	{
   607 	if(iPromptForced)
   608 		{
   609 		// Pormpt was forced therefore we must have matched an existing record in the
   610 		// database.
   611 		// Delete the old decision.
   612 		CDecisionFilter *filter = CDecisionFilter::NewLC();
   613 		filter->SetRecordId(iPromptForcedRecordId, EEqual);
   614 		TRAPD(err, UpsServer()->iDbHandle->RemoveDecisionsL(*filter));
   615 		CleanupStack::PopAndDestroy(filter);
   616 		if(err != KErrNone)
   617 			{
   618 			HandleDbErrorL(err);
   619 			}
   620 
   621 		// No longer disputing the record ID because we have a new decision
   622 		iPromptForced = EFalse;
   623 		UpsServer()->UnDisputeRecordIdL(iPromptForcedRecordId);
   624 		}
   625 	
   626 	TUpsDecisionPckgBuf decisionBuf;
   627 	// Mask out any illegal responses - ie buttons which we did not
   628 	// ask to be displayed...
   629 	iDialogSelectedOption = CPolicy::TOptions(TUint(iDialogSelectedOption) & TUint(iPolicy->Options()));
   630 	
   631 	decisionBuf() = MapCPolicyTOptions2TUpsDecision(iDialogSelectedOption);
   632 	
   633 	if((iDialogSelectedOption & CPolicy::EAlways) || (iDialogSelectedOption & CPolicy::ENever))
   634 		{
   635 
   636 		__ASSERT_ALWAYS(NULL != iDialogFingerprint,
   637 						User::Panic(KUpsServerName,
   638 								KErrUpsBadFingerprintLength));	
   639 	
   640 		// Save yes/no result to database
   641 		TPtrC8 clientEntityName(KNullDesC8());
   642 		if(iClientEntity)
   643 			{
   644 			clientEntityName.Set(iClientEntity->Name());
   645 			}
   646 		
   647 		CDecisionRecord *record = CDecisionRecord::NewLC(iPromptRequest->ClientSid(),
   648 														 iPolicy->PolicyEvaluator(),
   649 														 iPromptRequest->ServiceId(),
   650 														 iPromptRequest->ServerSid(),
   651 														 iDialogFingerprint->Fingerprint(),
   652 														 clientEntityName,
   653 														 iDialogFingerprint->Description(),
   654 														 ((iDialogSelectedOption & CPolicy::EAlways) != 0),
   655 														 iPolicy->MajorVersion(),
   656 														 iDialogEvaluatorInfo);
   657 		
   658 		// Create new record - Failure is not fatal...
   659 		TRAPD(err, UpsServer()->iDbHandle->CreateDecisionL(*record));
   660 		if(err == KErrAlreadyExists)
   661 			{
   662 			/// You might think this will never happen, but under OOM conditions it can/does. The original database query can fail,
   663 			/// even though there is a matching record in the database, we then choose to display a prompt, then the above code attempts to
   664 			/// insert a "new" record and fails.... We recover by just updating the existing record.
   665 			CDecisionFilter *filter = CDecisionFilter::NewLC(iPromptRequest->ClientSid(),
   666 															 iPolicy->PolicyEvaluator(),
   667 															 iPromptRequest->ServiceId(),
   668 															 iPromptRequest->ServerSid(),
   669 															 iDialogFingerprint->Fingerprint(),
   670 													 		 clientEntityName,
   671 													 		 iPolicy->MajorVersion());
   672 
   673 			TRAP(err, UpsServer()->iDbHandle->UpdateDecisionL(*filter, *record));
   674 			CleanupStack::PopAndDestroy(filter);
   675 			}
   676 		if(err != KErrNone)
   677 			{
   678 			HandleDbErrorL(err);
   679 			}
   680 		
   681 		CleanupStack::PopAndDestroy(record);
   682 		}
   683 
   684 	iMessagePtr2.WriteL(0, decisionBuf);
   685 	
   686 	CompleteAndMarkForDeletion(KErrNone);
   687 	}
   688 
   689 TUpsDecision CAuthoriser::MapCPolicyTOptions2TUpsDecision(CPolicy::TOptions aOptions)
   690 /**
   691 	Map the specified policy option bitmap (normally only a single bit should be set) into 
   692 	a TUpsDecision.
   693 
   694 	If the server supports session decisions, then return never/always as EUpsDecSessionNo/EUpsDecSessionYes.
   695 
   696 	Usually a single option should be specified, but we consider the options in the order which
   697 	minimises UPS traffic...
   698 */
   699 	{
   700 	if( (aOptions & (CPolicy::ENever | CPolicy::ESessionNo)) != 0)
   701 		{
   702 		// A Never - If the session supports "session no" then return it to cut down on UPS traffic
   703 		if(iPolicy->Options() & CPolicy::ESessionNo)
   704 			{
   705 			return EUpsDecSessionNo;
   706 			}
   707 		// Otherwise return "single shot no" so the server will re-query us later (we may silently answer).
   708 		return EUpsDecNo;
   709 		}
   710 
   711 	if( (aOptions & (CPolicy::EAlways| CPolicy::ESessionYes)) != 0)
   712 		{
   713 		// An Always - If the session supports "session yes" then return it to cut down on UPS traffic
   714 		if(iPolicy->Options() & CPolicy::ESessionYes)
   715 			{
   716 			return EUpsDecSessionYes;
   717 			}
   718 		// Otherwise return "single shot yes" so the server will re-query us later (so force prompt handling works).
   719 		return EUpsDecYes;
   720 		}
   721 
   722 	if( (aOptions & CPolicy::ENo) != 0)
   723 		{
   724 		// A "single shot no"
   725 		return EUpsDecNo;
   726 		}
   727 
   728 	// Only possibility left is a single shot yes
   729 	// If it is not one, then map to no
   730 	BULLSEYE_OFF
   731 	if( (aOptions & CPolicy::EYes) == 0)
   732 		{
   733 		return EUpsDecNo; // No option set!
   734 		}
   735 	BULLSEYE_RESTORE
   736 
   737 	// A "single shot yes"
   738 	return EUpsDecYes;
   739 	}
   740 
   741 void CAuthoriser::HandleDbErrorL(TInt aError)
   742 	{
   743 	if((aError != KErrNoMemory) && (aError != KErrDiskFull))
   744 		{
   745 		RDebug::Printf(KCorruptDb, aError, __LINE__);
   746 		UpsServer()->iDbHandle->DeleteDatabaseL(UpsServer()->iFs);
   747 		UpsServer()->iDbHandle.Close(); // Will auto-reopen when next used
   748 		User::Leave(aError);
   749 		}
   750 	UpsServer()->iDbHandle.Close(); // Will auto-reopen when next used
   751 	}
   752 
   753 CAuthoriserFifo* CAuthoriserFifo::NewL()
   754 	/**
   755 	   Create a new CAuthoriserFifo instance
   756 	*/
   757 	{
   758 	CAuthoriserFifo *self = new(ELeave) CAuthoriserFifo;
   759 	return self;
   760 	}
   761 
   762 CAuthoriserFifo::~CAuthoriserFifo()
   763 	/**
   764 	   Does not delete CAuthoriser objects in the FIFO, just frees
   765 	   storage used by the FIFO itself.
   766 	*/
   767 	{
   768 	iPtrArray.Close();
   769 	}
   770 
   771 
   772 
   773 void CAuthoriserFifo::PushL(CAuthoriser *aAuthoriser)
   774 	/**
   775 	   @param aAuthoriser The CAuthoriser to be pushed onto the FIFO.
   776 	   
   777 	   This class does NOT take ownership.
   778 	*/
   779 	{
   780 	iPtrArray.AppendL(aAuthoriser);
   781 	}
   782 
   783 CAuthoriser *CAuthoriserFifo::PopL()
   784 	{
   785 	/**
   786 	   @return A CAuthoriser ptr, or Leaves KErrUnderflow if FIFO is empty.
   787 	*/
   788 	TInt count = iPtrArray.Count();
   789 	BULLSEYE_OFF
   790 	if(count == 0)
   791 		{
   792 		User::Leave(KErrUnderflow);
   793 		}
   794 	BULLSEYE_RESTORE
   795 	
   796 	CAuthoriser *ret = iPtrArray[0];
   797 	iPtrArray.Remove(0);
   798 	return ret;
   799 	}
   800 
   801 void CAuthoriserFifo::RemoveL(CAuthoriser *aAuthoriser)
   802 	/**
   803 	   Remove the specified object from the FIFO.
   804 	   
   805 	   It is not considered to be an error if the object is not in the
   806 	   FIFO.
   807 	   
   808 	   @param aAuthoriser The CAuthoriser to be removed from the FIFO.
   809 	*/
   810 	{
   811 	TInt i = iPtrArray.Find(aAuthoriser);
   812 	BULLSEYE_OFF
   813 	if( i == KErrNotFound)
   814 		{
   815 		return; // Not found is not considered an error.
   816 		}
   817 	BULLSEYE_RESTORE
   818 	
   819 	User::LeaveIfError(i);
   820 	iPtrArray.Remove(i);
   821 	}
   822 
   823 
   824 TBool CAuthoriserFifo::IsEmpty() const
   825 	/**
   826 		@return ETrue if empty
   827 	 */
   828 	{
   829 	return (iPtrArray.Count() == 0);
   830 	}
   831 
   832 void CAuthoriserFifo::Compress()
   833 	/**
   834 	Reduce memory usage as much as possible. Typically used during OOM testing.
   835 	*/
   836 {
   837 	iPtrArray.Compress();
   838 }
   839 
   840 
   841 
   842 
   843 } // End of namespace UserPromptService
   844 // End of file