os/security/authorisation/userpromptservice/server/source/upsserver/upsserver.cpp
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