Add different root types of application: EXTENDED and SKEL.
This is connected with new places, where application can put
its own files.
Change-Id: I9f3db1523d0121dc6d094713a992a71b490c1976
{
std::string appId = getOwnAppId();
- PolicyEntry filter;
- filter.setApp(appId);
- filter.setUser(std::to_string(geteuid()));
- filter.setPrivilege(privilege);
+ auto policyLevel = getPrivilegePolicy(appId, privilege);
- PolicyFetchRequest fetch(std::move(filter));
- auto policies = fetch.fetchPolicy();
-
- if (policies.size() != 1) {
- ALOGE("Unusual situation, there are " << policies.size() <<
- " policies for (" << appId << ", " << geteuid() << ", " << privilege << ")");
- return ASKUSER_CHECK_RESULT_DENY;
- }
-
- auto level = policies.front().getLevel();
-
- if (level == "Allow") {
+ if (policyLevel == "Allow") {
return ASKUSER_CHECK_RESULT_ALLOW;
}
- if (level == "Deny") {
+ if (policyLevel == "Deny") {
return ASKUSER_CHECK_RESULT_DENY;
}
- if (level == "Ask user") {
+ if (policyLevel == "Ask user") {
return ASKUSER_CHECK_RESULT_ASK;
}
SET(COMMON_SOURCES
${COMMON_PATH}/log/alog.cpp
${COMMON_PATH}/policy/Policy.cpp
+ ${COMMON_PATH}/policy/PrivilegeInfo.cpp
${COMMON_PATH}/types/AgentErrorMsg.cpp
${COMMON_PATH}/util/SafeFunction.cpp
${COMMON_PATH}/config/Limits.cpp
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/common/policy/AppInfo.h
+ * @author Zofia Abramowska <z.abramowska@samsung.com>
+ * @brief Definition of pkgmgr-info wrappers
+ */
+
+#pragma once
+
+#include <string>
+#include <sys/types.h>
+#include <pkgmgr-info.h>
+
+#include <log/alog.h>
+
+namespace AskUser {
+
+struct AppInfo {
+ AppInfo(const std::string &appId, uid_t uid) : m_handle(nullptr) {
+ int ret = pkgmgrinfo_appinfo_get_usr_appinfo(appId.c_str(), uid, &m_handle);
+ if (ret != PMINFO_R_OK) {
+ ALOGE("pkgmgrinfo_appinfo_get_usr_appinfo failed for " << appId << " with " << ret);
+ m_handle = nullptr;
+ }
+ }
+ ~AppInfo() {
+ if (m_handle)
+ pkgmgrinfo_appinfo_destroy_appinfo(m_handle);
+ }
+ const std::string type() {
+ char *type = nullptr;
+ int ret = pkgmgrinfo_appinfo_get_apptype(m_handle, &type);
+ if (ret != PMINFO_R_OK) {
+ ALOGE("pkgmgrinfo_appinfo_get_apptype failed with " << ret);
+ return "";
+ }
+ return type ? type : "";
+ }
+
+ const std::string apiVersion() {
+ char *version = nullptr;
+ int ret = pkgmgrinfo_appinfo_get_api_version(m_handle, &version);
+ if (ret != PMINFO_R_OK) {
+ ALOGE("pkgmgrinfo_appinfo_get_api_version failed with " << ret);
+ return "";
+ }
+ return version ? version : "";
+ }
+
+ pkgmgrinfo_appinfo_h m_handle;
+};
+
+} // namespace AskUser
*/
#include <memory>
+#include <vector>
#include <security-manager.h>
#include "PkgInfo.h"
#include "Policy.h"
+#include "PrivilegeInfo.h"
+
+namespace AskUser {
namespace {
inline void throwOnSMError(std::string err, int ret)
if (ret == nullptr)
throw AskUser::Exception("SM returned null : " + err);
}
+
+} // namespace anonymous
+
+PolicyEntryCopy::PolicyEntryCopy(policy_entry *entry) {
+ const char *app;
+ throwOnSMNullptr("security_manager_policy_entry_get_application",
+ app = security_manager_policy_entry_get_application(entry));
+ m_appId = app;
+
+ const char *user;
+ throwOnSMNullptr("security_manager_policy_entry_get_user",
+ user = security_manager_policy_entry_get_user(entry));
+ m_user = user;
+
+ const char *privilege;
+ throwOnSMNullptr("security_manager_policy_entry_get_privilege",
+ privilege = security_manager_policy_entry_get_privilege(entry));
+ m_privilege = privilege;
+
+ const char *level;
+ throwOnSMNullptr("security_manager_policy_entry_get_level",
+ level = security_manager_policy_entry_get_level(entry));
+ m_level = level;
}
-namespace AskUser {
+Policy getMinimumPolicy(const std::vector<Policy> &policies) {
+ Policy minimumPolicy = "Allow";
+
+ for (auto &policy : policies) {
+ if (policy == "Deny") {
+ minimumPolicy = "Deny";
+ break;
+ } else if (policy != minimumPolicy && policy == "Ask user") {
+ minimumPolicy = "Ask user";
+ }
+ }
+ return minimumPolicy;
+}
+
+Policy calculatePolicyForPrivacy(const std::string &appId, const Privacy &privacy) {
+ ALOGD("Calculating privacy " << privacy);
+ std::vector<Policy> privsPolicies;
+ auto privileges = PrivilegeInfo::getPrivacyPrivileges(privacy);
+ for (const auto &privilege : privileges) {
+ ALOGD("Calculating policy for privilege " << privilege);
+ PolicyEntry filter;
+ filter.setApp(appId);
+ filter.setUser(std::to_string(geteuid()));
+ filter.setPrivilege(privilege);
+
+ PolicyFetchRequest fetch(std::move(filter));
+ auto policies = fetch.fetchPolicy();
+ if (policies.size() == 0) {
+ ALOGD("No policy for given privilege " << privilege);
+ continue;
+ }
+ if (policies.size() > 1) {
+ ALOGW("Something went wrong, there should be no more than one policy for specific filter");
+ // FIXME : don't really know what to do with it. Lets ignore it for now.
+ continue;
+ }
+ std::string policyLevel = policies[0].getLevel();
+ ALOGD("Fetched policy level : " << policyLevel);
+
+ privsPolicies.push_back(std::move(policyLevel));
+ }
+ return getMinimumPolicy(privsPolicies);
+}
+
+Policy getPrivaciesPolicy(const std::string &appId, const std::vector<Privacy> &privacies) {
+ std::vector<Policy> policies;
+ for (auto &privacy : privacies) {
+ policies.push_back(calculatePolicyForPrivacy(appId, privacy));
+ }
+ return getMinimumPolicy(policies);
+}
void identifyApp(const std::string &client, std::string &appId, std::string &pkgLabel)
{
pkgLabel = pkgInfo.pkgLabel();
}
+Policy getPrivilegePolicy(const std::string &appId, const std::string &privilege) {
+ std::vector<Privacy> privacies = PrivilegeInfo::getPrivilegePrivaciesMapping(appId, privilege);
+ if (privacies.empty()) {
+ ALOGE("Privilege doesn't map to any privacy");
+ return "";
+ }
+
+ return getPrivaciesPolicy(appId, privacies);
+}
+
std::string getOwnAppId()
{
char *pkgName = nullptr;
return std::string();
}
-PolicyEntry::PolicyEntry() {
+PolicyEntry::PolicyEntry() : m_entry(nullptr) {
throwOnSMError("security_manager_policy_entry_new",
security_manager_policy_entry_new(&m_entry));
}
const char *level;
throwOnSMNullptr("security_manager_policy_entry_get_level",
level = security_manager_policy_entry_get_level(m_entry));
+ ALOGD("Level : " << level);
return level;
}
}
-std::vector<PolicyEntry> PolicyFetchRequest::fetchPolicy() {
+std::vector<PolicyEntryCopy> PolicyFetchRequest::fetchPolicy() {
policy_entry **pp_entries;
size_t p_size;
throwOnSMError("security_manager_get_configured_policy_for_self",
security_manager_policy_entries_free(*p, p_size);
}
);
- std::vector<PolicyEntry> entries;
- for(size_t i = 0; i < p_size; i++) {
- entries.emplace_back(PolicyEntry(pp_entries[i]));
+ std::vector<PolicyEntryCopy> entries;
+ for (size_t i = 0; i < p_size; i++) {
+ entries.emplace_back(PolicyEntryCopy(pp_entries[i]));
}
ppPtr.release();
return entries;
#include <string>
#include <vector>
+#include <types/PolicyTypes.h>
+
struct policy_entry;
struct policy_update_req;
namespace AskUser {
-void identifyApp(const std::string &client, std::string &appId, std::string &pkgLabel);
std::string getOwnAppId();
+void identifyApp(const std::string &client, std::string &appId, std::string &pkgLabel);
+
+Policy getPrivilegePolicy(const std::string &appId, const Privilege &privilege);
+Policy getPrivaciesPolicy(const std::string &appId, const std::vector<Privacy> &privacies);
+
class PolicyEntry {
public:
policy_entry *m_entry;
};
+class PolicyEntryCopy {
+public:
+ PolicyEntryCopy() = default;
+ PolicyEntryCopy(PolicyEntryCopy &&other) = default;
+ PolicyEntryCopy(policy_entry *entry);
+ ~PolicyEntryCopy() = default;
+ std::string getAppId() { return m_appId; }
+ std::string getUser() { return m_user; }
+ std::string getPrivilege() { return m_privilege; }
+ std::string getLevel() { return m_level; }
+
+private:
+ std::string m_appId;
+ std::string m_user;
+ std::string m_privilege;
+ std::string m_level;
+};
+
class PolicyRequest {
public:
PolicyRequest();
public:
PolicyFetchRequest(PolicyEntry &&filter) : m_filter(std::move(filter)) {}
~PolicyFetchRequest() {}
- std::vector<PolicyEntry> fetchPolicy();
+ std::vector<PolicyEntryCopy> fetchPolicy();
private:
PolicyEntry m_filter;
};
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/agent/notification-daemon/Privilege.cpp
+ * @author Zofia Abramowska <z.abramowska@samsung.com>
+ * @brief Implementation of Privilege Info wrappers
+ */
+
+#include <cstdlib>
+#include <memory>
+#include <set>
+
+#include "PrivilegeInfo.h"
+
+#include <exception/Exception.h>
+#include <log/alog.h>
+#include <policy/AppInfo.h>
+
+#include <privilegemgr/privilege_info.h>
+#include <privilegemgr/privilege_db_manager.h>
+#include <pkgmgr-info.h>
+#include <glib.h>
+
+
+namespace AskUser {
+
+namespace PrivilegeInfo {
+
+namespace {
+
+class GListWrap {
+public:
+ GListWrap() : m_head(nullptr) {
+ m_head = g_list_alloc();
+ if (!m_head) {
+ ALOGE("Failed to allocate glib list");
+ // FIXME : throw
+ }
+ }
+
+ GListWrap(GList *_list) : m_head(_list) {}
+
+ ~GListWrap() { g_list_free(m_head);}
+
+ void append(gpointer data) {
+ GList *newHead = g_list_prepend(m_head, data);
+ if (newHead == nullptr) {
+ ALOGE("Failed to prepend the glib list");
+ return;
+ }
+ m_head = newHead;
+ }
+ GList * get() { return m_head; }
+
+private:
+ GList *m_head;
+};
+
+std::vector<Privacy> getPrivilegesPrivacies(const std::vector<std::string> &corePrivileges) {
+ std::set<Privacy> privaciesSet;
+ for (auto &privilege : corePrivileges) {
+ ALOGD("Getting privacy for privilege : " << privilege);
+ if (!isPrivacy(privilege)) {
+ ALOGD("Privilege " << privilege << " is not privacy, skipping");
+ continue;
+ }
+ Privacy privacy = getPrivacyName(privilege);
+ if (privacy.empty()) {
+ // FIXME: should we abort whole request or ignore privilege which cannot be mapped to privacy?
+ ALOGE("Something went wrong with fetching privacy name for " << privilege << ", aborting");
+ return {};
+ } else {
+ ALOGD("Privilege belongs to privacy " << privacy);
+ }
+ privaciesSet.insert(privacy);
+ }
+ return std::vector<Privacy>(privaciesSet.begin(), privaciesSet.end());
+}
+
+std::vector<Privilege> getPrivilegeMapping(const std::string &appId, const Privilege &privilege) {
+ ALOGD("Mapping privilege " << privilege);
+ AppInfo app(appId, geteuid());
+ std::string version = app.apiVersion();
+ std::string type = app.type();
+
+ if (version.empty() || type.empty()) {
+ ALOGE("Failed to fetch application version and type");
+ return {};
+ }
+ ALOGD("App " << appId << " is of type " << type << " and version " << version);
+
+ privilege_manager_package_type_e pkgType;
+ if (type == "c++app" || type == "capp") {
+ pkgType = PRVMGR_PACKAGE_TYPE_CORE;
+ } else if (type == "webapp") {
+ pkgType = PRVMGR_PACKAGE_TYPE_WRT;
+ } else {
+ ALOGD("Application type not supported by mapping : " << type);
+ return {privilege};
+ }
+
+ GListWrap privList;
+ privList.append(const_cast<void*>(static_cast<const void *>(privilege.c_str())));
+
+ GList *privMapped = nullptr;
+ int ret = privilege_db_manager_get_mapped_privilege_list(version.c_str(), pkgType, privList.get(), &privMapped);
+ if (ret != PRVMGR_ERR_NONE || !privMapped) {
+ ALOGE("Unable to get mapping of privilege " << privilege << "; err: <" << ret << ">");
+ return {};
+ }
+
+ GListWrap privMappedWrap(privMapped);
+ std::vector<std::string> privMappedVector;
+ for (GList *l = privMappedWrap.get(); l != NULL; l = l->next) {
+ std::string corePriv = static_cast<char*>(l->data);
+ ALOGD("Privilege mapps to " << corePriv);
+ privMappedVector.push_back(std::move(corePriv));
+ }
+
+ return privMappedVector;
+}
+
+
+} //namespace anonymous
+
+bool isPrivacy(const Privilege &privilege) {
+ return privilege_info_is_privacy(privilege.c_str()) == 1;
+}
+
+std::string getPrivacyDisplayName(const Privacy &privacy) {
+ char *displayName = nullptr;
+ int ret = privilege_info_get_privacy_display(privacy.c_str(), &displayName);
+ if (ret != PRVMGR_ERR_NONE || !displayName) {
+ ALOGE("Unable to get privacy display name for <" << privacy << ">, err: <" << ret << ">");
+ return privacy;
+ }
+ std::unique_ptr<char, decltype(free)*> displaNamePtr(displayName, free);
+ return std::string(displayName);
+}
+
+Privacy getPrivacyName(const Privilege &privilege) {
+ char* privacyName = nullptr;
+ int ret = privilege_info_get_privacy_by_privilege(privilege.c_str(), &privacyName);
+ if (ret != PRVMGR_ERR_NONE || !privacyName) {
+ ALOGE("Unable to get privacy group for privilege: <" << privilege << ">, err: <" << ret << ">");
+ return privilege;
+ }
+
+ std::unique_ptr<char, decltype(free) *> privacyNamePtr(privacyName, free);
+ return std::string(privacyName);
+}
+
+std::vector<Privilege> getPrivacyPrivileges(const Privacy &privacy) {
+ GList *privilegeList = nullptr;
+
+ int ret = privilege_info_get_privilege_list_by_privacy(privacy.c_str(), &privilegeList);
+ if (ret != PRVMGR_ERR_NONE || !privilegeList) {
+ ALOGE("Unable to get privacy group list of privileges; err: <" << ret << ">");
+ return {privacy};
+ }
+
+ GListWrap privList(privilegeList);
+ std::vector<Privilege> privVector;
+ for (GList *l = privList.get(); l != NULL; l = l->next) {
+ privVector.push_back(static_cast<char*>(l->data));
+ }
+ return privVector;
+}
+
+
+std::vector<Privacy> getPrivilegePrivaciesMapping(const std::string &appId, const std::string &privilege) {
+ std::vector<std::string> corePrivileges = PrivilegeInfo::getPrivilegeMapping(appId, privilege);
+ if (corePrivileges.empty()) {
+ ALOGE("Cannot fetch mapping for application " << appId << " and privilege " << privilege << ", aborting");
+ return {};
+ }
+
+ return getPrivilegesPrivacies(corePrivileges);
+}
+
+}
+} /* namespace AskUser */
#include <string>
#include <vector>
+#include <types/PolicyTypes.h>
+
namespace AskUser {
namespace PrivilegeInfo {
- std::string getPrivacyDisplayName(const std::string &privilege);
- std::string getPrivacyName(const std::string &privilege);
- std::vector<std::string> getPrivacyPrivileges(const std::string &privacy);
+ std::vector<Privacy> getPrivilegePrivaciesMapping(const std::string &appId, const std::string &privilege);
+ bool isPrivacy(const Privilege &privilege);
+ Privacy getPrivacyName(const Privacy &privilege);
+ std::string getPrivacyDisplayName(const Privacy &privacy);
+
+ std::vector<Privilege> getPrivacyPrivileges(const Privacy &privacy);
};
} /* namespace AskUser */
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+/**
+ * @file PolicyTypes.h
+ * @author Zofia Grzelewska <z.abramowska@samsung.com>
+ * @brief The definition of Policy types
+ */
+
+#pragma once
+#include <string>
+
+namespace AskUser {
+
+typedef std::string Privilege;
+typedef std::string Privacy;
+typedef std::string Policy;
+
+} // namespace AskUser
${NOTIF_PATH}/main.cpp
${NOTIF_PATH}/Logic.cpp
${NOTIF_PATH}/PolicyUpdater.cpp
+ ${NOTIF_PATH}/PrivaciesSequence.cpp
${NOTIF_PATH}/ServerCallbacks.cpp
- ${NOTIF_PATH}/policy/PrivilegeInfo.cpp
${NOTIF_PATH}/ui/Po.cpp
${NOTIF_PATH}/ui/Popupper.cpp
)
#include <policy/Policy.h>
#include "PolicyUpdater.h"
#include "ServerCallbacks.h"
+#include "policy/PrivilegeInfo.h"
+
namespace AskUser {
namespace Notification {
+namespace {
+
+int uiResponseToClientResponse(NResponseType response) {
+ int clientResponse;
+
+ switch (response) {
+ case NResponseType::Deny:
+ clientResponse = ASKUSER_DENY_ONCE;
+ break;
+ case NResponseType::DenyAlways:
+ clientResponse = ASKUSER_DENY_FOREVER;
+ break;
+ case NResponseType::Allow:
+ case NResponseType::AllowAlways:
+ clientResponse = ASKUSER_ALLOW_FOREVER;
+ break;
+ case NResponseType::None:
+ clientResponse = ASKUSER_NONE;
+ break;
+ case NResponseType::Error:
+ clientResponse = ASKUSER_UNKNOWN_ERROR;
+ break;
+ default:
+ clientResponse = ASKUSER_UNKNOWN_ERROR;
+ }
+
+ return clientResponse;
+}
+
+std::string clientResponseToPolicy(int clientResponse) {
+ std::string level;
+
+ switch (clientResponse) {
+ case ASKUSER_DENY_FOREVER:
+ level = "Deny";
+ break;
+ case ASKUSER_ALLOW_FOREVER:
+ level = "Allow";
+ break;
+ default :
+ level = "Ask user";
+ }
+
+ return level;
+}
+
+}
+
void Logic::addChannelFd(Protocol::ConnectionFd fd, const Protocol::Credentials &creds) {
auto it = m_connToInfo.find(fd);
if (it != m_connToInfo.end()) {
return;
}
+ if (creds.uid != std::to_string(geteuid())) {
+ ALOGE("This is very unexpected, client with different uid connected : " << creds.uid);
+ m_serverChannel->process(fd, 0);
+ }
+
std::string appId, pkgLabel;
identifyApp(creds.label, appId, pkgLabel);
ConnectionInfo connInfo{appId, pkgLabel, creds.uid};
}
void Logic::removeChannelFd(Protocol::ConnectionFd fd) {
- m_connToInfo.erase(fd);
-
auto it = m_fdInfo.find(fd);
if (it == m_fdInfo.end()) {
return;
[fd](const FdEvent &fdEvent) {return fdEvent.id.fd == fd;});
m_pendingEvents.erase(queueIt, m_pendingEvents.end());
+ // Ignore error in policy setting, we can't do anything about it nor we can inform user about error
+ (void)setPolicy(m_connToInfo[fd], "Ask user");
+ m_connToInfo.erase(fd);
+ m_fdInfo.erase(fd);
+ m_serverChannel->process(fd, 0);
+
// Handle next event if removed active fd
if (fd == m_currentEvent.fd) {
- finishCurrentEvent();
+ finishCurrentRequest();
processEvents();
}
- m_fdInfo.erase(fd);
- m_serverChannel->process(fd, 0);
return ECORE_CALLBACK_CANCEL;
}
case FdChange::CHANGE:
}
}
-void Logic::addEvent(EventId id, IUIEvent *event) {
- FdEvent fdEvent{id, std::unique_ptr<IUIEvent>(event)};
+void Logic::addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::vector<Privacy> &privacies) {
+ EventId eventId{fd, id};
+ PrivaciesSequence &seq = m_eventToPrivaciesSeq[eventId];
+ seq.setPrivacies(privacies);
+
+ ConnectionInfo &conn = m_connToInfo[fd];
+
+ Privacy currentPrivacy;
+ seq.getNextPrivacy(currentPrivacy);
+
+ FdEvent fdEvent{eventId, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgLabel, currentPrivacy))};
m_pendingEvents.emplace_back(std::move(fdEvent));
- processEvents();
}
void Logic::popup(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::string &privilege) {
+ ALOGD("Request for privilege " << privilege);
+
auto it = m_connToInfo.find(fd);
if (it == m_connToInfo.end()) {
ALOGE("Got request to non existing fd " << fd);
return;
}
+ ConnectionInfo &conn = it->second;
- PolicyEntry filter;
- filter.setApp(it->second.appId);
- filter.setUser(it->second.user);
- filter.setPrivilege(privilege);
-
- PolicyFetchRequest fetch(std::move(filter));
- auto policies = fetch.fetchPolicy();
-
- if (policies.size() == 0) {
- ALOGE("No policy for (" << it->second.appId << ", " << it->second.user << ", " << privilege << ")");
- m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
- return;
- }
-
- if (policies.size() > 1) {
- ALOGE("Something strange happened, more than one policy for (" << it->second.appId << ", "
- << it->second.user << ", " << privilege << ") exists");
+ std::vector<Privacy> privacies = PrivilegeInfo::getPrivilegePrivaciesMapping(conn.appId, privilege);
+ if (privacies.empty()) {
+ ALOGE("Privilege " << privilege << " doesn't map to any privacy");
m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
return;
}
- std::string policyLevel = policies.front().getLevel();
+ Policy policyLevel = getPrivaciesPolicy(conn.appId, privacies);
+ ALOGD("Privilege policy level calculated to : " << policyLevel);
if (policyLevel == "Allow") {
m_serverChannel->popupResponse(fd, id, ASKUSER_ALLOW_FOREVER);
return;
return;
}
if (policyLevel != "Ask user") {
- ALOGE("Unknown policy set : " << policyLevel << " for (" << it->second.appId << ", " << it->second.user
- << ", " << privilege << ")" );
+ ALOGE("Unknown policy set : " << policyLevel << " for (" << conn.appId << ", " << conn.user
+ << ", " << privilege << ")");
m_serverChannel->popupResponse(fd, id, ASKUSER_DENY_ONCE);
return;
}
- auto &pkgId = it->second.pkgLabel;
- addEvent({fd, id}, new EventPopupCheck(&m_popupper, pkgId, privilege));
+ addEvent(fd, id, privacies);
+ processEvents();
}
Logic::~Logic()
return m_currentEvent.fd != Protocol::INVALID_FD;
}
-void Logic::finishCurrentEvent() {
+void Logic::finishCurrentRequest() {
+ m_eventToPrivaciesSeq.erase(m_currentEvent);
m_popupper.popupClose();
+
m_currentEvent = EventId();
if (!m_pendingEvents.empty())
m_pendingEvents.pop_front();
}
void Logic::stop() {
- if (isEventProcessed())
- finishCurrentEvent();
+ if (isEventProcessed()) {
+ ConnectionInfo &conn = m_connToInfo[m_currentEvent.fd];
+ processResponse(conn, ASKUSER_DENY_ONCE, "Ask user");
+ finishCurrentRequest();
+ }
m_popupper.stop();
}
m_popupper.shutdown();
}
-void Logic::respondAndContinue(int response) {
- m_serverChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, response);
- finishCurrentEvent();
- processEvents();
+bool Logic::setPolicy(const ConnectionInfo &conn, const std::string &lastPolicy) {
+ std::string currentPrivacy;
+
+ PrivaciesSequence &privSeq = m_eventToPrivaciesSeq[m_currentEvent];
+ if (!privSeq.getCurrentPrivacy(currentPrivacy)) {
+ ALOGD("Privilege is allowed completely");
+ }
+
+ privSeq.rewind();
+
+ Privacy privacy;
+ while (privSeq.getNextPrivacy(privacy) && privacy != currentPrivacy) {
+ /*
+ * When privacy is not allowed with deny forever or deny once, then processing is stopped,
+ * so all privacies, which were already processed, are allowed.
+ */
+ if (!PolicyUpdater::update(conn.appId, privacy, "Allow")) {
+ // FIXME : Maybe ignore those errors and try to maintain the policy as consistent as we can?
+ ALOGE("Couldn't set policy for " << conn.appId << " privacy : " << privacy << " level : Allow");
+ return false;
+ }
+ }
+
+ if (!currentPrivacy.empty() && lastPolicy != "Ask user") {
+ /*
+ * setPolicy is called when privacy processing is either successfully finished or
+ * aborted due to error, so currentPrivacy will be empty in the first case and
+ * we don't set policy when user responds with "Deny once" (this translates to "Ask user")
+ */
+ if (!PolicyUpdater::update(conn.appId, currentPrivacy, lastPolicy)) {
+ ALOGE("Couldn't set policy for " << conn.appId << " privacy : " << privacy << " level : " << lastPolicy);
+ }
+ }
+ return true;
+}
+
+void Logic::processResponse(const ConnectionInfo &conn, int clientResponse, const Policy &level) {
+ if (!setPolicy(conn, level)) {
+ m_serverChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, ASKUSER_UNKNOWN_ERROR);
+ } else {
+ m_serverChannel->popupResponse(m_currentEvent.fd, m_currentEvent.id, clientResponse);
+ }
}
void Logic::popupResponse(NResponseType response) {
ALOGE("Got response from inactive fd " << m_currentEvent.fd);
return;
}
-
- EventPopupCheck *event = dynamic_cast<EventPopupCheck*>(m_pendingEvents.front().event.get());
- if (!event) {
- ALOGE("Something went really wrong - couldn't cast event to EventPopupCheck");
- respondAndContinue(ASKUSER_UNKNOWN_ERROR);
- return;
- }
-
- int clientResponse;
- std::string level;
- // TODO translate ui response to policy result
- switch (response) {
- case NResponseType::Deny:
- clientResponse = ASKUSER_DENY_ONCE;
- break;
- case NResponseType::DenyAlways:
- clientResponse = ASKUSER_DENY_FOREVER;
- level = "Deny";
- break;
- case NResponseType::Allow:
- case NResponseType::AllowAlways:
- clientResponse = ASKUSER_ALLOW_FOREVER;
- level = "Allow";
- break;
- case NResponseType::None:
- clientResponse = ASKUSER_NONE;
- break;
- case NResponseType::Error:
- clientResponse = ASKUSER_UNKNOWN_ERROR;
- break;
- default:
- clientResponse = ASKUSER_UNKNOWN_ERROR;
- }
- if (!level.empty()) {
- if (!PolicyUpdater::update(it->second.appId, event->getPrivilege(), level)) {
- ALOGE("Failed to update policy, returning DENY_ONCE in this case");
- clientResponse = ASKUSER_DENY_ONCE;
+ ConnectionInfo &conn = it->second;
+
+ int clientResponse = uiResponseToClientResponse(response);
+ std::string level = clientResponseToPolicy(clientResponse);
+ if (clientResponse != ASKUSER_ALLOW_FOREVER) {
+ // Privacy not allowed, request is denied
+ processResponse(conn, clientResponse, level);
+ finishCurrentRequest();
+ processEvents();
+ } else {
+ // Privacy allowed - check if more privacies are to process
+ PrivaciesSequence &seq = m_eventToPrivaciesSeq[m_currentEvent];
+ Privacy nextPrivacy;
+ if (seq.getNextPrivacy(nextPrivacy)) {
+ // More privacies to process - replace existing event with new privacy
+ FdEvent fdEvent{m_currentEvent, std::unique_ptr<IUIEvent>(new EventPopupCheck(&m_popupper, conn.pkgLabel, nextPrivacy))};
+ m_pendingEvents[0] = std::move(fdEvent);
+ // don't call finishCurrentRequest here, because it will pop event, which we replaced
+ m_currentEvent = EventId();
+ processEvents();
+ } else {
+ // No more privacies, request is allowed
+ processResponse(it->second, clientResponse, level);
+ finishCurrentRequest();
+ processEvents();
}
}
-
- respondAndContinue(clientResponse);
}
} // namespace Notification
#include <map>
#include <deque>
#include <server-channel.h>
-#include <event/Event.h>
+
+#include "event/Event.h"
+#include "PrivaciesSequence.h"
namespace AskUser {
EventId(Protocol::ConnectionFd _fd, Protocol::RequestId _id) : fd(_fd), id(_id) {}
Protocol::ConnectionFd fd;
Protocol::RequestId id;
+
+ bool operator<(const EventId &rhs) const {
+ return (fd < rhs.fd) || ((fd == rhs.fd) && (id < rhs.id));
+ }
+ };
+
+ struct ConnectionInfo {
+ std::string appId;
+ std::string pkgLabel;
+ std::string user;
};
//Initialization
static Eina_Bool signalHandler(void *data, Ecore_Fd_Handler *handler);
//static Eina_Bool signalHandler(void *data, int type, void *event);
- void addEvent(EventId id, IUIEvent *event);
+ void addEvent(Protocol::ConnectionFd fd, Protocol::RequestId id, const std::vector<Privacy> &privacies);
Eina_Bool processChannel(int fd, int mask);
bool identifyClient(const std::string &label, std::string &appId, std::string &pkgId);
void processEvents();
+ void processResponse(const ConnectionInfo &conn, int clientResponse, const Policy &level);
bool isEventProcessed();
- void finishCurrentEvent();
+ void finishCurrentRequest();
void popupResponse(NResponseType response);
- void respondAndContinue(int response);
+
+ bool processError(EventId id, int error);
+ bool setPolicy(const ConnectionInfo &conn, const std::string &lastPolicy);
std::unique_ptr<AskUser::Protocol::ServerChannel> m_serverChannel;
Popupper m_popupper;
std::map<Protocol::ConnectionFd, FdInfo> m_fdInfo;
- struct ConnectionInfo {
- std::string appId;
- std::string pkgLabel;
- std::string user;
- };
+
std::map<Protocol::ConnectionFd, ConnectionInfo> m_connToInfo;
+
+ std::map<EventId, PrivaciesSequence> m_eventToPrivaciesSeq;
};
} // namespace Notification
namespace Notification {
bool PolicyUpdater::update(const std::string &appId,
- const std::string &privilege, const std::string &level)
+ const std::string &privacy, const std::string &level)
{
try {
- ALOGD("Policy update for: app: " << appId << ", privilege: " << privilege
+ ALOGD("Generating policy update for: app: " << appId << ", privacy: " << privacy
<< ", user:" << geteuid() << ", level: " << level);
static const std::string user = std::to_string(geteuid());
PolicyRequest req;
- std::string privacyName = PrivilegeInfo::getPrivacyName(privilege);
- if (privacyName.empty()) {
- ALOGE("Unable to get privacy name for privilege " << privilege);
- throw Exception("Unable to get privacy name for " + privilege);
- }
- auto privacyPrivs = PrivilegeInfo::getPrivacyPrivileges(privacyName);
+ auto privacyPrivs = PrivilegeInfo::getPrivacyPrivileges(privacy);
if (privacyPrivs.empty()) {
- ALOGE("Unable to get privacy privileges for privacy " << privacyName);
- throw Exception("Unable to get privacy privileges for privacy " + privacyName);
+ ALOGE("Unable to get privacy privileges for privacy " << privacy);
+ throw Exception("Unable to get privacy privileges for privacy " + privacy);
}
- ALOGD("Adding policy entry for : app: " << appId << ", privilege: "
- << privilege << ", user:" << user << ", level: "
- << level);
+
for (auto &priv : privacyPrivs) {
+ ALOGD("Adding policy entries for : app: " << appId << ", priv: "
+ << priv << ", user:" << user << ", level: "
+ << level);
PolicyEntry entry;
entry.setApp(appId);
entry.setUser(user);
namespace Notification {
namespace PolicyUpdater {
- bool update(const std::string &appId, const std::string &privilege,
+ bool update(const std::string &appId, const std::string &privacy,
const std::string &level);
};
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+/**
+ * @file PrivaciesSequence.cpp
+ * @author Zofia Grzelewska <z.abramowska@samsung.com>
+ * @brief The implementation of PrivaciesSequence
+ */
+
+#include "PrivaciesSequence.h"
+
+namespace AskUser {
+
+namespace Notification {
+
+PrivaciesSequence::PrivaciesSequence() : m_currentPrivacy(m_privacies.begin()), m_nextPrivacy(m_privacies.begin())
+{}
+
+void PrivaciesSequence::rewind() {
+ m_currentPrivacy = m_privacies.begin();
+ m_nextPrivacy = m_privacies.begin();
+}
+
+void PrivaciesSequence::setPrivacies(const std::vector<Privacy> &privacies) {
+ m_privacies = privacies;
+ m_currentPrivacy = m_privacies.begin();
+ m_nextPrivacy = m_privacies.begin();
+}
+
+bool PrivaciesSequence::getCurrentPrivacy(Privacy &privacy) {
+ if (m_currentPrivacy == m_privacies.end())
+ return false;
+ privacy = *m_currentPrivacy;
+ return true;
+}
+
+bool PrivaciesSequence::getNextPrivacy(Privacy &privacy) {
+ m_currentPrivacy = m_nextPrivacy;
+ if (m_currentPrivacy == m_privacies.end())
+ return false;
+ privacy = *m_currentPrivacy;
+ m_nextPrivacy++;
+ return true;
+}
+
+} // namespace Notification
+
+} // namespace AskUser
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+/**
+ * @file PrivaciesSequence.h
+ * @author Zofia Grzelewska <z.abramowska@samsung.com>
+ * @brief The definition of PrivaciesSequence
+ */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <types/PolicyTypes.h>
+
+namespace AskUser {
+
+namespace Notification {
+
+/*
+ * Container allowing sequential access to privacy vector
+ */
+class PrivaciesSequence {
+public:
+ PrivaciesSequence();
+ void setPrivacies(const std::vector<Privacy> &privacies);
+ /*
+ * Get next privacy in sequence. Returns false, when there is no more privacies.
+ */
+ bool getNextPrivacy(Privacy &privacy);
+
+ /*
+ * Get current privacy in sequence.
+ */
+ bool getCurrentPrivacy(Privacy &privacy);
+
+ /*
+ * Rewind to the beginning of privacy sequence.
+ */
+ void rewind();
+
+ virtual ~PrivaciesSequence() {}
+private:
+ typedef std::vector<Privacy> PrivacyVector;
+ PrivacyVector m_privacies;
+ PrivacyVector::iterator m_currentPrivacy;
+ PrivacyVector::iterator m_nextPrivacy;
+};
+
+}
+
+}
class EventPopupCheck : public IUIEvent {
public:
- EventPopupCheck(Popupper *popupper, const std::string &pkgLabel, const std::string &privilege)
- : IUIEvent(popupper), m_pkgLabel(pkgLabel), m_privilege(privilege)
+ EventPopupCheck(Popupper *popupper, const std::string &pkgLabel, const std::string &privacy)
+ : IUIEvent(popupper), m_pkgLabel(pkgLabel), m_privacy(privacy)
{}
- std::string getPrivilege() {
- return m_privilege;
- }
-
virtual void process() {
- m_popupper->popupCheck(m_pkgLabel, m_privilege);
+ m_popupper->popupCheck(m_pkgLabel, m_privacy);
}
private:
std::string m_pkgLabel;
- std::string m_privilege;
+ std::string m_privacy;
};
} //namespace AskUser
+++ /dev/null
-/*
- * Copyright (c) 2016 Samsung Electronics Co.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-/**
- * @file src/agent/notification-daemon/Privilege.cpp
- * @author Zofia Abramowska <z.abramowska@samsung.com>
- * @brief Implementation of Privilege Info wrappers
- */
-
-#include <cstdlib>
-#include <memory>
-
-#include "PrivilegeInfo.h"
-
-#include <exception/Exception.h>
-#include <log/alog.h>
-
-#include <privilegemgr/privilege_info.h>
-#include <glib.h>
-
-namespace AskUser {
-
-struct GListWrap {
- GListWrap(GList *_list) : list(_list) {}
- ~GListWrap() { g_list_free_full(list, free);}
- GList * get() { return list; }
- GList *list;
-};
-
-namespace PrivilegeInfo {
-
-std::string getPrivacyDisplayName(const std::string &privilege) {
- char *displayName = nullptr;
- int ret = privilege_info_get_privacy_display(getPrivacyName(privilege).c_str(), &displayName);
- if (ret != PRVMGR_ERR_NONE || !displayName) {
- ALOGE("Unable to get privacy display name for <" << privilege << ">, err: <" << ret << ">");
- return privilege;
- }
- std::unique_ptr<char, decltype(free)*> displaNamePtr(displayName, free);
- return std::string(displayName);
-}
-
-std::string getPrivacyName(const std::string &privilege) {
- char* privacyName = nullptr;
- int ret = privilege_info_get_privacy_by_privilege(privilege.c_str(), &privacyName);
- if (ret != PRVMGR_ERR_NONE || !privacyName) {
- ALOGE("Unable to get privacy group for privilege: <" << privilege << ">, err: <" << ret << ">");
- return privilege;
- }
-
- std::unique_ptr<char, decltype(free) *> privacyNamePtr(privacyName, free);
- return std::string(privacyName);
-}
-
-std::vector<std::string> getPrivacyPrivileges(const std::string &privacy) {
- GList *privilegeList = nullptr;
-
- int ret = privilege_info_get_privilege_list_by_privacy(privacy.c_str(), &privilegeList);
- if (ret != PRVMGR_ERR_NONE || !privilegeList) {
- ALOGE("Unable to get privacy group list of privileges; err: <" << ret << ">" );
- return {privacy};
- }
-
- GListWrap privList(privilegeList);
- std::vector<std::string> privVector;
- for (GList *l = privList.get(); l != NULL; l = l->next) {
- privVector.push_back(static_cast<char*>(l->data));
- }
- return privVector;
-}
-
-}
-} /* namespace AskUser */
{MsgType::MSG_POPUP_TEXT, "IDS_IDLE_POP_ALLOW_P1SS_TO_ACCESS_YOUR_P2SS_Q"},
{MsgType::MSG_POPUP_LAUNCH_TEXT, "IDS_IDLE_POP_PS_IS_REQUESTING_PERMISSION_TO_ACCESS_THE_FOLLOWING_ITEMS_C"},
{MsgType::MSG_POPUP_CHECKBOX, "IDS_ST_OPT_DONT_SHOW_AGAIN"},
- {MsgType::MSG_POPUP_ALLOW_BTN,"IDS_IDLE_BUTTON_ALLOW_ABB7"},
+ {MsgType::MSG_POPUP_ALLOW_BTN, "IDS_IDLE_BUTTON_ALLOW_ABB7"},
{MsgType::MSG_POPUP_DENY_BTN, "IDS_IDLE_BUTTON_DENY"},
{MsgType::MSG_TOAST_DENY_TEXT, "IDS_ST_TPOP_P1SS_NOT_ALLOWED_TO_USE_P2SS_SELECT_PRIVACY_SETTINGS_IN_SETTINGS_PRIVACY_AND_SECURITY"},
{MsgType::MSG_TOAST_FAIL_TEXT, "IDS_IDLE_TPOP_TO_USE_APP_ALLOW_ALL_RELEVANT_PERMISSIONS"}
namespace Notification {
namespace Po {
-std::string createPopupCheckMsg(const std::string &pkgLabel, const std::string &priv) {
+std::string createPopupCheckMsg(const std::string &pkgLabel, const std::string &privacy) {
return makeFromFormat(getFormat(MsgType::MSG_POPUP_TEXT), pkgLabel.c_str(),
- PrivilegeInfo::getPrivacyDisplayName(priv).c_str());
+ PrivilegeInfo::getPrivacyDisplayName(privacy).c_str());
}
std::string getPopupTitleMsg() {
evas_object_show(m_win);
}
-void Popupper::popupCheck(const std::string &pkgLabel, const std::string &priv) {
+void Popupper::popupCheck(const std::string &pkgLabel, const std::string &privacy) {
std::string profileName = getProfileName();
PopupCheck *popup;
try {
if (profileName[0] != 'w' && profileName[0] != 'W') {
// Not wearable
- popup = new PopupCheckMobile(m_win, Po::createPopupCheckMsg(pkgLabel, priv));
+ popup = new PopupCheckMobile(m_win, Po::createPopupCheckMsg(pkgLabel, privacy));
} else {
// Wearable
- popup = new PopupCheckWearable(m_win, Po::createPopupCheckMsg(pkgLabel, priv));
+ popup = new PopupCheckWearable(m_win, Po::createPopupCheckMsg(pkgLabel, privacy));
}
popup->create();
} catch (const std::exception &e) {
void registerPopupResponseHandler(PopupHandler handler);
void start();
- void popupCheck(const std::string &pkgLabel, const std::string &priv);
+ void popupCheck(const std::string &pkgLabel, const std::string &privacy);
void popupClose();
void stop();