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>
40 #include <dpl/foreach.h>
44 Request::ApplicationType getAppType(const Request *request) {
45 AceDB::AppTypes appType =
46 AceDB::AceDAOReadOnly::getWidgetType(request->getWidgetHandle());
48 case AceDB::AppTypes::Tizen:
49 LogDebug("==== Found Tizen application. ====");
50 return Request::APP_TYPE_TIZEN;
51 case AceDB::AppTypes::WAC20:
52 LogDebug("==== Found Wac20 application. ====");
53 return Request::APP_TYPE_WAC20;
55 LogDebug("==== Unknown application type. ====");
57 return Request::APP_TYPE_UNKNOWN;
60 } // anonymous namespace
62 void SecurityLogic::initialize() {
63 AceDB::AceDAO::attachToThreadRW();
64 m_policyEnforcementPoint.initialize(new WebRuntimeImpl(),
65 new ResourceInformationImpl(),
66 new OperationSystemImpl());
69 void SecurityLogic::terminate() {
70 m_policyEnforcementPoint.terminate();
71 AceDB::AceDAO::detachFromThread();
75 void SecurityLogic::grantPlatformAccess(const Request& request)
78 #ifdef WRT_SMACK_ENABLED
80 unsigned long long id =
81 static_cast<unsigned long long>(request.getWidgetHandle());
82 Request::DeviceCapabilitySet dc = request.getDeviceCapabilitySet();
84 size_t i,size = dc.size();
85 std::unique_ptr<const char*[]> array(new const char*[size+1]);
90 for(i=0; (i<size) && (it!=dc.end()); ++i,++it) {
91 array[i] = it->c_str();
93 int ret = wrt_permissions_add(id, array.get());
94 if (PC_OPERATION_SUCCESS != ret) {
95 LogError("smack rules couldn't be granted");
97 } catch (std::bad_alloc&) {
98 LogError("smack rules couldn't be granted: memory allocation failed");
103 PolicyResult SecurityLogic::checkFunctionCall(Request* request)
105 Assert(NULL != request);
107 LogDebug("=== Check widget existance ===");
109 request->setAppType(getAppType(request));
110 } Catch (AceDB::AceDAOReadOnly::Exception::DatabaseError) {
111 LogError("==== Couldn't find widget for handle: " <<
112 request->getWidgetHandle() << ". Access denied. ====");
113 return PolicyEffect::DENY;
116 PolicyResult aceResult = m_policyEnforcementPoint.check(*request).policyResult;
118 if (aceResult == PolicyEffect::PERMIT) {
119 grantPlatformAccess(*request);
120 return PolicyEffect::PERMIT;
121 } else if (aceResult == PolicyEffect::PROMPT_ONESHOT ||
122 aceResult == PolicyEffect::PROMPT_SESSION ||
123 aceResult == PolicyEffect::PROMPT_BLANKET ||
124 aceResult == PolicyDecision::NOT_APPLICABLE ||
125 aceResult == PolicyResult::UNDETERMINED)
127 // TODO: check stored user answers!!!
128 // if necessary, grant SMACK rules
129 // return appropriately - the following is a dummy:
132 return PolicyEffect::DENY;
136 PolicyResult SecurityLogic::checkFunctionCall(Request* request, const std::string &sessionId)
138 Assert(NULL != request);
139 LogDebug("=== Check existance of widget === ");
141 request->setAppType(getAppType(request));
142 } Catch (AceDB::AceDAOReadOnly::Exception::DatabaseError) {
143 LogError("==== Couldn't find widget for handle: " <<
144 request->getWidgetHandle() << ". Access denied. ====");
145 return PolicyEffect::DENY;
148 ExtendedPolicyResult exAceResult = m_policyEnforcementPoint.check(*request);
149 PolicyResult aceResult = exAceResult.policyResult;
151 LogDebug("Result returned by policy " << aceResult << ". RuleID: " << exAceResult.ruleId);
153 if (aceResult == PolicyEffect::PERMIT) {
154 LogDebug("Grant access.");
155 grantPlatformAccess(*request);
156 return PolicyEffect::PERMIT;
159 if (aceResult == PolicyEffect::PROMPT_ONESHOT ||
160 aceResult == PolicyEffect::DENY)
165 OptionalCachedPromptDecision decision = AceDB::AceDAOReadOnly::getPromptDecision(
166 request->getWidgetHandle(),
170 LogDebug("No CachedPromptDecision found.");
174 if (aceResult == PolicyEffect::PROMPT_BLANKET) {
175 if (decision->decision == PromptDecision::ALLOW_ALWAYS) {
176 LogDebug("Found user decision. Result changed to PERMIT. Access granted");
177 grantPlatformAccess(*request);
178 return PolicyEffect::PERMIT;
180 if (decision->decision == PromptDecision::DENY_ALWAYS) {
181 LogDebug("Found user decision. Result changed to DENY.");
182 return PolicyEffect::DENY;
184 if (decision->decision == PromptDecision::ALLOW_FOR_SESSION
185 && !!(decision->session)
186 && sessionId == DPL::ToUTF8String(*(decision->session)))
188 LogDebug("Result changed to PERMIT. Access granted.");
189 grantPlatformAccess(*request);
190 return PolicyEffect::PERMIT;
192 if (decision->decision == PromptDecision::DENY_FOR_SESSION
193 && !!(decision->session)
194 && sessionId == DPL::ToUTF8String(*(decision->session)))
196 LogDebug("Found user decision. Result changed to DENY.");
197 return PolicyEffect::DENY;
202 if (aceResult == PolicyEffect::PROMPT_SESSION) {
203 if (decision->decision == PromptDecision::ALLOW_FOR_SESSION
204 && !!(decision->session)
205 && sessionId == DPL::ToUTF8String(*(decision->session)))
207 LogDebug("Found user decision. Result changed to PERMIT. Access granted.");
208 grantPlatformAccess(*request);
209 return PolicyEffect::PERMIT;
211 if (decision->decision == PromptDecision::DENY_FOR_SESSION
212 && !!(decision->session)
213 && sessionId == DPL::ToUTF8String(*(decision->session)))
215 LogDebug("Found user decision. Result changed to DENY.");
216 return PolicyEffect::DENY;
221 // This should not happend - all PolicyEffect values were supported before.
222 // This mean that someone has modyfied PolicyEffect enum. SPANK SPANK SPANK
223 LogError("Unsupported PolicyEffect!");
224 return PolicyEffect::DENY;
227 void SecurityLogic::validatePopupResponse(Request* request,
229 Prompt::Validity validity,
230 const std::string& sessionId,
233 Assert(NULL != retValue);
234 Assert(NULL != request);
237 LogDebug("User answered: " << allowed << " with validity: " << validity);
238 LogDebug("Check widget existance");
240 request->setAppType(getAppType(request));
241 } Catch (AceDB::AceDAOReadOnly::Exception::DatabaseError) {
242 LogError("==== Couldn't find widget for handle: " <<
243 request->getWidgetHandle() << ". Access denied. ====");
249 OptionalExtendedPolicyResult extendedAceResult =
250 m_policyEnforcementPoint.checkFromCache(*request);
251 if (!extendedAceResult) {
252 LogDebug("No cached policy result - but it should be here");
253 LogDebug("returning " << *retValue);
257 PolicyResult aceResult = extendedAceResult->policyResult;
258 if (aceResult == PolicyEffect::DENY) {
259 LogDebug("returning " << *retValue);
262 if (aceResult == PolicyEffect::PERMIT) {
263 // TODO we were asked for prompt validation
264 // but we got that no prompt should be opened - is this OK?
265 // (this is on the diagram in wiki)
267 } else if (aceResult == PolicyEffect::PROMPT_ONESHOT ||
268 aceResult == PolicyEffect::PROMPT_SESSION ||
269 aceResult == PolicyEffect::PROMPT_BLANKET)
271 Request::DeviceCapabilitySet devCaps =
272 request->getDeviceCapabilitySet();
274 FOREACH (it, devCaps) {
275 Request::DeviceCapability resourceId = *it;
276 LogDebug("Recheck: " << *it);
277 // 1) check if per-widget settings permit
278 AceDB::PreferenceTypes wgtPref =
279 AceDB::AceDAOReadOnly::getWidgetDevCapSetting(
281 request->getWidgetHandle());
282 if (AceDB::PreferenceTypes::PREFERENCE_DENY == wgtPref) {
283 LogDebug("returning " << *retValue);
286 // 2) check if per-dev-cap settings permit
287 AceDB::PreferenceTypes resPerf =
288 AceDB::AceDAOReadOnly::getDevCapSetting(resourceId);
289 if (AceDB::PreferenceTypes::PREFERENCE_DENY == resPerf) {
290 LogDebug("returning " << *retValue);
294 // 3) check for stored propmt answer - should not be there
295 // TODO - is this check necessary?
296 AceDB::BaseAttributeSet attributes;
297 AceDB::AceDAOReadOnly::getAttributes(&attributes);
298 Request req(request->getWidgetHandle(),
299 request->getExecutionPhase());
300 req.addDeviceCapability(resourceId);
301 PolicyInformationPoint *pip =
302 m_policyEnforcementPoint.getPip();
306 pip->getAttributesValues(&req, &attributes);
307 auto attrHash = AceDB::AceDaoConversions::convertToHash(attributes);
309 // 4) validate consistency of answer with policy result
310 Prompt::Validity clampedValidity =
311 clampPromptValidity(validity, *(aceResult.getEffect()));
313 // 5) store answer in database if appropriate
314 // TODO how about userParam? sessionId?
315 DPL::String userParam = DPL::FromUTF8String(sessionId);
316 boost::optional<DPL::String> sessionOptional = 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; }