2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * This class simply redirects the access requests to access control engine.
18 * The aim is to hide access control engine specific details from WRT modules.
19 * It also implements WRT_INTERFACE.h interfaces, so that ACE could access
20 * WRT specific and other information during the decision making.
22 * @file security_controller.h
23 # @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
24 * @author Ming Jin(ming79.jin@samsung.com)
25 * @author Piotr Kozbial (p.kozbial@samsung.com)
27 * @brief Header file for security logic
30 #include <security_logic.h>
31 #include <attribute_facade.h>
32 #ifdef WRT_SMACK_ENABLED
33 #include <privilege-control.h>
35 #include <ace-dao-rw/AceDAO.h>
36 #include <ace-dao-ro/AceDAOConversions.h>
37 #include <ace/PolicyInformationPoint.h>
38 #include <ace/PromptDecision.h>
39 #include <dpl/log/log.h>
43 Request::ApplicationType getAppType(const Request *request) {
44 AceDB::AppTypes appType =
45 AceDB::AceDAOReadOnly::getWidgetType(request->getWidgetHandle());
47 case AceDB::AppTypes::Tizen:
48 LogDebug("==== Found Tizen application. ====");
49 return Request::APP_TYPE_TIZEN;
50 case AceDB::AppTypes::WAC20:
51 LogDebug("==== Found Wac20 application. ====");
52 return Request::APP_TYPE_WAC20;
54 LogDebug("==== Unknown application type. ====");
56 return Request::APP_TYPE_UNKNOWN;
59 } // anonymous namespace
61 void SecurityLogic::initialize() {
62 AceDB::AceDAO::attachToThreadRW();
63 m_policyEnforcementPoint.initialize(new WebRuntimeImpl(),
64 new ResourceInformationImpl(),
65 new OperationSystemImpl());
68 void SecurityLogic::terminate() {
69 m_policyEnforcementPoint.terminate();
70 AceDB::AceDAO::detachFromThread();
74 void SecurityLogic::grantPlatformAccess(const Request& request)
77 #ifdef WRT_SMACK_ENABLED
79 unsigned long long id =
80 static_cast<unsigned long long>(request.getWidgetHandle());
81 Request::DeviceCapabilitySet dc = request.getDeviceCapabilitySet();
83 size_t i,size = dc.size();
84 std::unique_ptr<const char*[]> array(new const char*[size+1]);
89 for(i=0; (i<size) && (it!=dc.end()); ++i,++it) {
90 array[i] = it->c_str();
92 int ret = wrt_permissions_add(id, array.get());
93 if (PC_OPERATION_SUCCESS != ret) {
94 LogError("smack rules couldn't be granted");
96 } catch (std::bad_alloc&) {
97 LogError("smack rules couldn't be granted: memory allocation failed");
102 PolicyResult SecurityLogic::checkFunctionCall(Request* request)
104 Assert(NULL != request);
106 LogDebug("=== Check widget existance ===");
108 request->setAppType(getAppType(request));
109 } Catch (AceDB::AceDAOReadOnly::Exception::DatabaseError) {
110 LogError("==== Couldn't find widget for handle: " <<
111 request->getWidgetHandle() << ". Access denied. ====");
112 return PolicyEffect::DENY;
115 PolicyResult aceResult = m_policyEnforcementPoint.check(*request).policyResult;
117 if (aceResult == PolicyEffect::PERMIT) {
118 grantPlatformAccess(*request);
119 return PolicyEffect::PERMIT;
120 } else if (aceResult == PolicyEffect::PROMPT_ONESHOT ||
121 aceResult == PolicyEffect::PROMPT_SESSION ||
122 aceResult == PolicyEffect::PROMPT_BLANKET ||
123 aceResult == PolicyDecision::NOT_APPLICABLE ||
124 aceResult == PolicyResult::UNDETERMINED)
126 // TODO: check stored user answers!!!
127 // if necessary, grant SMACK rules
128 // return appropriately - the following is a dummy:
131 return PolicyEffect::DENY;
135 PolicyResult SecurityLogic::checkFunctionCall(Request* request, const std::string &sessionId)
137 Assert(NULL != request);
138 LogDebug("=== Check existance of widget === ");
140 request->setAppType(getAppType(request));
141 } Catch (AceDB::AceDAOReadOnly::Exception::DatabaseError) {
142 LogError("==== Couldn't find widget for handle: " <<
143 request->getWidgetHandle() << ". Access denied. ====");
144 return PolicyEffect::DENY;
147 ExtendedPolicyResult exAceResult = m_policyEnforcementPoint.check(*request);
148 PolicyResult aceResult = exAceResult.policyResult;
150 LogDebug("Result returned by policy " << aceResult << ". RuleID: " << exAceResult.ruleId);
152 if (aceResult == PolicyEffect::PERMIT) {
153 LogDebug("Grant access.");
154 grantPlatformAccess(*request);
155 return PolicyEffect::PERMIT;
158 if (aceResult == PolicyEffect::PROMPT_ONESHOT ||
159 aceResult == PolicyEffect::DENY)
164 OptionalCachedPromptDecision decision = AceDB::AceDAOReadOnly::getPromptDecision(
165 request->getWidgetHandle(),
168 if (decision.IsNull()) {
169 LogDebug("No CachedPromptDecision found.");
173 if (aceResult == PolicyEffect::PROMPT_BLANKET) {
174 if (decision->decision == PromptDecision::ALLOW_ALWAYS) {
175 LogDebug("Found user decision. Result changed to PERMIT. Access granted");
176 grantPlatformAccess(*request);
177 return PolicyEffect::PERMIT;
179 if (decision->decision == PromptDecision::DENY_ALWAYS) {
180 LogDebug("Found user decision. Result changed to DENY.");
181 return PolicyEffect::DENY;
183 if (decision->decision == PromptDecision::ALLOW_FOR_SESSION
184 && !(decision->session.IsNull())
185 && sessionId == DPL::ToUTF8String(*(decision->session)))
187 LogDebug("Result changed to PERMIT. Access granted.");
188 grantPlatformAccess(*request);
189 return PolicyEffect::PERMIT;
191 if (decision->decision == PromptDecision::DENY_FOR_SESSION
192 && !(decision->session.IsNull())
193 && sessionId == DPL::ToUTF8String(*(decision->session)))
195 LogDebug("Found user decision. Result changed to DENY.");
196 return PolicyEffect::DENY;
201 if (aceResult == PolicyEffect::PROMPT_SESSION) {
202 if (decision->decision == PromptDecision::ALLOW_FOR_SESSION
203 && !(decision->session.IsNull())
204 && sessionId == DPL::ToUTF8String(*(decision->session)))
206 LogDebug("Found user decision. Result changed to PERMIT. Access granted.");
207 grantPlatformAccess(*request);
208 return PolicyEffect::PERMIT;
210 if (decision->decision == PromptDecision::DENY_FOR_SESSION
211 && !(decision->session.IsNull())
212 && sessionId == DPL::ToUTF8String(*(decision->session)))
214 LogDebug("Found user decision. Result changed to DENY.");
215 return PolicyEffect::DENY;
220 // This should not happend - all PolicyEffect values were supported before.
221 // This mean that someone has modyfied PolicyEffect enum. SPANK SPANK SPANK
222 LogError("Unsupported PolicyEffect!");
223 return PolicyEffect::DENY;
226 void SecurityLogic::validatePopupResponse(Request* request,
228 Prompt::Validity validity,
229 const std::string& sessionId,
232 Assert(NULL != retValue);
233 Assert(NULL != request);
236 LogDebug("User answered: " << allowed << " with validity: " << validity);
237 LogDebug("Check widget existance");
239 request->setAppType(getAppType(request));
240 } Catch (AceDB::AceDAOReadOnly::Exception::DatabaseError) {
241 LogError("==== Couldn't find widget for handle: " <<
242 request->getWidgetHandle() << ". Access denied. ====");
248 OptionalExtendedPolicyResult extendedAceResult =
249 m_policyEnforcementPoint.checkFromCache(*request);
250 if (extendedAceResult.IsNull()) {
251 LogDebug("No cached policy result - but it should be here");
252 LogDebug("returning " << *retValue);
256 PolicyResult aceResult = extendedAceResult->policyResult;
257 if (aceResult == PolicyEffect::DENY) {
258 LogDebug("returning " << *retValue);
261 if (aceResult == PolicyEffect::PERMIT) {
262 // TODO we were asked for prompt validation
263 // but we got that no prompt should be opened - is this OK?
264 // (this is on the diagram in wiki)
266 } else if (aceResult == PolicyEffect::PROMPT_ONESHOT ||
267 aceResult == PolicyEffect::PROMPT_SESSION ||
268 aceResult == PolicyEffect::PROMPT_BLANKET)
270 Request::DeviceCapabilitySet devCaps =
271 request->getDeviceCapabilitySet();
273 FOREACH (it, devCaps) {
274 Request::DeviceCapability resourceId = *it;
275 LogDebug("Recheck: " << *it);
276 // 1) check if per-widget settings permit
277 AceDB::PreferenceTypes wgtPref =
278 AceDB::AceDAOReadOnly::getWidgetDevCapSetting(
280 request->getWidgetHandle());
281 if (AceDB::PreferenceTypes::PREFERENCE_DENY == wgtPref) {
282 LogDebug("returning " << *retValue);
285 // 2) check if per-dev-cap settings permit
286 AceDB::PreferenceTypes resPerf =
287 AceDB::AceDAOReadOnly::getDevCapSetting(resourceId);
288 if (AceDB::PreferenceTypes::PREFERENCE_DENY == resPerf) {
289 LogDebug("returning " << *retValue);
293 // 3) check for stored propmt answer - should not be there
294 // TODO - is this check necessary?
295 AceDB::BaseAttributeSet attributes;
296 AceDB::AceDAOReadOnly::getAttributes(&attributes);
297 Request req(request->getWidgetHandle(),
298 request->getExecutionPhase());
299 req.addDeviceCapability(resourceId);
300 PolicyInformationPoint *pip =
301 m_policyEnforcementPoint.getPip();
305 pip->getAttributesValues(&req, &attributes);
306 auto attrHash = AceDB::AceDaoConversions::convertToHash(attributes);
308 // 4) validate consistency of answer with policy result
309 Prompt::Validity clampedValidity =
310 clampPromptValidity(validity, *(aceResult.getEffect()));
312 // 5) store answer in database if appropriate
313 // TODO how about userParam? sessionId?
314 DPL::String userParam = DPL::FromUTF8String(sessionId);
315 DPL::OptionalString sessionOptional =
316 DPL::FromUTF8String(sessionId);
318 switch (clampedValidity) {
319 case Prompt::Validity::ALWAYS: {
320 AceDB::AceDAO::setPromptDecision(
321 request->getWidgetHandle(),
322 extendedAceResult->ruleId,
325 PromptDecision::ALLOW_ALWAYS :
326 PromptDecision::DENY_ALWAYS);
328 case Prompt::Validity::SESSION: {
329 AceDB::AceDAO::setPromptDecision(
330 request->getWidgetHandle(),
331 extendedAceResult->ruleId,
334 PromptDecision::ALLOW_FOR_SESSION :
335 PromptDecision::DENY_FOR_SESSION);
338 case Prompt::Validity::ONCE: {
339 LogInfo("Validity ONCE, not saving prompt decision to cache");
348 // 6) grant smack label if not granted yet
349 grantPlatformAccess(*request);
352 LogDebug("returning " << *retValue);
355 void SecurityLogic::updatePolicy()
357 LogDebug("SecurityLogic::updatePolicy");
358 m_policyEnforcementPoint.updatePolicy();
361 Prompt::Validity SecurityLogic::clampPromptValidity(
362 Prompt::Validity validity,
366 case PolicyEffect::PROMPT_BLANKET: {
368 case PolicyEffect::PROMPT_SESSION: {
369 if (Prompt::Validity::ALWAYS == validity) {
370 LogInfo("ALWAYS returned from prompt in PROMPT_SESSION");
371 return Prompt::Validity::SESSION;
374 case PolicyEffect::PROMPT_ONESHOT: {
375 if (Prompt::Validity::ONCE != validity) {
376 LogInfo("Not ONCE returned from prompt in PROMPT_ONESHOT");
378 return Prompt::Validity::ONCE; }
379 case PolicyEffect::DENY:
380 case PolicyEffect::PERMIT:
381 default: {// other options - should not happen
382 LogError("This kind of policy effect does not deal with prompts");
383 return Prompt::Validity::ONCE; }