Privilege privacy status (& default policy) now relies also on UID and application.
This patch introduces integration with privilege-checker API that allows to check
privilege status in context of these attributes.
Change-Id: I8bf25cf708ed21a7af9cc047f01fff3ff8410dcc
${COMMON_PATH}/smack-check.cpp
${COMMON_PATH}/service_impl.cpp
${COMMON_PATH}/tzplatform-config.cpp
+ ${COMMON_PATH}/privilege-info.cpp
)
IF(DPL_WITH_DLOG)
#include <dpl/errno_string.h>
#include <config.h>
#include <utils.h>
+#include <privilege-info.h>
namespace SecurityManager {
void CynaraAdmin::UpdateAppPolicy(
const std::string &label,
- const std::string &user,
- const std::vector<std::string> &privileges,
- std::function <bool(const std::string &, const std::string &)> isPrivacy)
-{
- auto calcPolicies = [&](
- const std::string &user,
- const std::vector<std::string> &privileges,
- const std::string &bucket,
- int policyToSet,
- std::vector<CynaraAdminPolicy> &policies)
- {
- std::vector<CynaraAdminPolicy> oldPolicies;
- std::unordered_set<std::string> privilegesSet(privileges.begin(),
- privileges.end());
- ListPolicies(bucket, label, user,
- CYNARA_ADMIN_ANY, oldPolicies);
-
- // Compare previous policies with set of new requested privileges
- for (auto &policy : oldPolicies) {
- if (privilegesSet.erase(policy.privilege)) {
- // privilege was found and removed from the set, keeping policy
- LogDebug("(user = " << user << " label = " << label << ") " <<
- "keeping privilege " << policy.privilege);
- } else {
- // privilege was not found in the set, deleting policy
- policy.result = static_cast<int>(CynaraAdminPolicy::Operation::Delete);
- LogDebug("(user = " << user << " label = " << label << ") " <<
- "removing privilege " << policy.privilege);
- }
- policies.push_back(std::move(policy));
- }
-
- // Add policies for privileges that weren't previously enabled
- // Those that were previously enabled are now removed from privilegesSet
- for (const auto &privilege : privilegesSet) {
- LogDebug("(user = " << user << " label = " << label << ") " <<
- "adding privilege " << privilege);
- policies.push_back(CynaraAdminPolicy(label, user, privilege, policyToSet, bucket));
- }
- };
-
+ bool global,
+ uid_t uid,
+ const std::vector<std::string> &privileges)
+{
std::vector<CynaraAdminPolicy> policies;
+ std::string cynaraUser;
+ if (global)
+ cynaraUser = CYNARA_ADMIN_WILDCARD;
+ else
+ cynaraUser = std::to_string(static_cast<unsigned int>(uid));
+
// 1st, performing operation on MANIFESTS bucket
- calcPolicies(user, privileges, Buckets.at(Bucket::MANIFESTS),
+ CalculatePolicies(label, cynaraUser, privileges, Buckets.at(Bucket::MANIFESTS),
static_cast<int>(CynaraAdminPolicy::Operation::Allow),
policies);
+ bool askUserEnabled = false;
+ int askUserPolicy = static_cast<int>(CynaraAdminPolicy::Operation::Allow);
if (Config::IS_ASKUSER_ENABLED) {
try {
- int askUserPolicy = convertToPolicyType(Config::PRIVACY_POLICY_DESC);
-
- std::vector<std::string> privacyPrivileges;
- for (auto &p : privileges)
- if (isPrivacy(label, p))
- privacyPrivileges.push_back(p);
-
- // 2nd, performing operation on PRIVACY_MANAGER bucket for all affected users
- if (user == CYNARA_ADMIN_WILDCARD) {
- // perform bucket setting for all users in the system, app is installed for everyone
- std::vector<uid_t> users;
- ListUsers(users);
- for (uid_t id : users) {
- calcPolicies(std::to_string(id), privacyPrivileges,
- Buckets.at(Bucket::PRIVACY_MANAGER),
- askUserPolicy, policies);
- }
- } else {
- // local single user installation, do it only for that particular user
- calcPolicies(user, privacyPrivileges, Buckets.at(Bucket::PRIVACY_MANAGER),
- askUserPolicy, policies);
- }
+ askUserPolicy = convertToPolicyType(Config::PRIVACY_POLICY_DESC);
+ askUserEnabled = true;
} catch (const std::out_of_range&) {
+ // Cynara doesn't know "Ask user"
LogDebug("Unknown policy level: " << Config::PRIVACY_POLICY_DESC);
- };
+ }
+ }
+
+ // 2nd, performing operation on PRIVACY_MANAGER bucket for all affected users
+ std::vector<uid_t> users;
+ if (cynaraUser == CYNARA_ADMIN_WILDCARD) {
+ // perform bucket setting for all users in the system, app is installed for everyone
+ ListUsers(users);
+ } else {
+ // local single user installation, do it only for that particular user
+ users.push_back(uid);
+ }
+
+ for (uid_t id : users) {
+ std::vector<std::string> blacklistPrivileges;
+ std::vector<std::string> privacyPrivileges;
+ for (auto &p : privileges) {
+ PrivilegeInfo priv(id, label, p);
+ if (askUserEnabled && priv.hasAttribute(PrivilegeInfo::PrivilegeAttr::PRIVACY))
+ privacyPrivileges.push_back(p);
+ if (priv.hasAttribute(PrivilegeInfo::PrivilegeAttr::BLACKLIST))
+ blacklistPrivileges.push_back(p);
+ }
+ CalculatePolicies(label, std::to_string(id), privacyPrivileges,
+ Buckets.at(Bucket::PRIVACY_MANAGER),
+ askUserPolicy, policies);
+ CalculatePolicies(label, std::to_string(id), blacklistPrivileges,
+ Buckets.at(Bucket::ADMIN),
+ static_cast<int>(CynaraAdminPolicy::Operation::Deny), policies);
}
+
SetPolicies(policies);
}
}
}
-void CynaraAdmin::UserInit(uid_t uid, security_manager_user_type userType,
- std::function <bool(const std::string &, const std::string &)> isPrivacy)
+void CynaraAdmin::UserInit(uid_t uid, security_manager_user_type userType)
{
Bucket bucket;
std::vector<CynaraAdminPolicy> policies;
}
policies.push_back(CynaraAdminPolicy(CYNARA_ADMIN_WILDCARD,
- userStr,
- CYNARA_ADMIN_WILDCARD,
- Buckets.at(bucket),
- Buckets.at(Bucket::MAIN)));
-
+ userStr,
+ CYNARA_ADMIN_WILDCARD,
+ Buckets.at(bucket),
+ Buckets.at(Bucket::MAIN)));
+
+ std::vector<CynaraAdminPolicy> appPolicies;
+ ListPolicies(CynaraAdmin::Buckets.at(Bucket::MANIFESTS),
+ CYNARA_ADMIN_ANY, CYNARA_ADMIN_WILDCARD,
+ CYNARA_ADMIN_ANY, appPolicies);
+
+ int askUserPolicy = static_cast<int>(CynaraAdminPolicy::Operation::Allow);
+ bool askUserEnabled = false;
if (Config::IS_ASKUSER_ENABLED) {
try{
- // for each global app: retrieve its privacy-related privileges and set
- // their policy in PRIVACY_MANAGER bucket to "Ask user"
-
- int askUserPolicy = convertToPolicyType(Config::PRIVACY_POLICY_DESC);
-
- std::vector<CynaraAdminPolicy> appPolicies;
- ListPolicies(CynaraAdmin::Buckets.at(Bucket::MANIFESTS),
- CYNARA_ADMIN_ANY, CYNARA_ADMIN_WILDCARD,
- CYNARA_ADMIN_ANY, appPolicies);
-
- for (CynaraAdminPolicy &policy : appPolicies)
- if (isPrivacy(policy.client, policy.privilege))
- policies.push_back(CynaraAdminPolicy(policy.client,
- userStr,
- policy.privilege,
- askUserPolicy,
- Buckets.at(Bucket::PRIVACY_MANAGER)));
+ askUserPolicy = convertToPolicyType(Config::PRIVACY_POLICY_DESC);
+ askUserEnabled = true;
} catch (const std::out_of_range&) {
+ // Cynara doesn't know "Ask user"
LogDebug("Unknown policy level: " << Config::PRIVACY_POLICY_DESC);
- };
+ }
+ }
+
+ // for each global app: retrieve its privacy-related abnd blacklist privileges and set
+ // their policy in PRIVACY_MANAGER bucket accordingly
+ for (CynaraAdminPolicy &policy : appPolicies) {
+ try {
+ PrivilegeInfo priv(uid, policy.client, policy.privilege);
+ if (askUserEnabled && priv.hasAttribute(PrivilegeInfo::PrivilegeAttr::PRIVACY))
+ policies.push_back(CynaraAdminPolicy(
+ policy.client,
+ userStr,
+ policy.privilege,
+ askUserPolicy,
+ Buckets.at(Bucket::PRIVACY_MANAGER)));
+ if (priv.hasAttribute(PrivilegeInfo::PrivilegeAttr::BLACKLIST))
+ policies.push_back(CynaraAdminPolicy(
+ policy.client,
+ userStr,
+ policy.privilege,
+ static_cast<int>(CynaraAdminPolicy::Operation::Deny),
+ Buckets.at(Bucket::ADMIN)));
+ } catch (const PrivilegeInfo::Exception::NotApplication&) {
+ continue;
+ }
+
+
}
SetPolicies(policies);
m_policyDescriptionsInitialized = true;
}
+
+void CynaraAdmin::CalculatePolicies(const std::string &label, const std::string &user,
+ const std::vector<std::string> &privileges,
+ const std::string &bucket, int policyToSet,
+ std::vector<CynaraAdminPolicy> &policies)
+{
+ std::vector<CynaraAdminPolicy> oldPolicies;
+ std::unordered_set<std::string> privilegesSet(privileges.begin(),
+ privileges.end());
+ ListPolicies(bucket, label, user, CYNARA_ADMIN_ANY, oldPolicies);
+ // Compare previous policies with set of new requested privileges
+ for (auto &policy : oldPolicies) {
+ if (privilegesSet.erase(policy.privilege)) {
+ // privilege was found and removed from the set, keeping policy
+ LogDebug("(user = " << user << " label = " << label << ") " <<
+ "keeping privilege " << policy.privilege);
+ } else {
+ // privilege was not found in the set, deleting policy
+ policy.result = static_cast<int>(CynaraAdminPolicy::Operation::Delete);
+ LogDebug("(user = " << user << " label = " << label << ") " <<
+ "removing privilege " << policy.privilege);
+ }
+ policies.push_back(std::move(policy));
+ }
+ // Add policies for privileges that weren't previously enabled
+ // Those that were previously enabled are now removed from privilegesSet
+ for (const auto &privilege : privilegesSet) {
+ LogDebug("(user = " << user << " label = " << label << ") " <<
+ "adding privilege " << privilege);
+ policies.push_back(CynaraAdminPolicy(label, user, privilege, policyToSet, bucket));
+ }
+}
+
void CynaraAdmin::ListPoliciesDescriptions(std::vector<std::string> &policiesDescriptions)
{
FetchCynaraPolicyDescriptions(false);
#include <mutex>
#include <thread>
#include <future>
-#include <functional>
#include <poll.h>
#include <sys/eventfd.h>
* Caller must have permission to access Cynara administrative socket.
*
* @param label application Smack label
- * @param user user identifier
+ * @param global true if it's a global or preloaded installation
+ * @param uid user identifier
* @param privileges currently enabled privileges
- * @param isPrivacy a function that checks if privilege is privacy-related
*/
- void UpdateAppPolicy(const std::string &label, const std::string &user,
- const std::vector<std::string> &privileges,
- std::function <bool(const std::string &, const std::string &)> isPrivacy);
+ void UpdateAppPolicy(const std::string &label, bool global, uid_t uid,
+ const std::vector<std::string> &privileges);
/**
* Fetch Cynara policies for the application and the user.
*
* @param uid new user uid
* @param userType type as enumerated in security-manager.h
- * @param isPrivacy a function that checks if privilege is privacy-related
*/
- void UserInit(uid_t uid, security_manager_user_type userType,
- std::function <bool(const std::string &, const std::string &)> isPrivacy);
+ void UserInit(uid_t uid, security_manager_user_type userType);
/**
* List all users registered in Cynara
*/
void FetchCynaraPolicyDescriptions(bool forceRefresh = false);
+ /**
+ * Calculate actual Cynara policy based on appilcation data & previous policy
+ *
+ * @param label application identifier
+ * @param user user for which we are calculating the policy
+ * @param privileges new privielges for which policy is being calulated
+ * @param bucket bucket to which the policy will be set
+ * @param policyToSet policy effect to be set
+ * @param policies current policy (input/output parameter)
+ */
+ void CalculatePolicies(const std::string &label, const std::string &user,
+ const std::vector<std::string> &privileges,
+ const std::string &bucket, int policyToSet,
+ std::vector<CynaraAdminPolicy> &policies);
+
struct cynara_admin *m_CynaraAdmin;
static TypeToDescriptionMap TypeToDescription;
--- /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 privilege-info.h
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ */
+
+#pragma once
+
+#include <string>
+#include <functional>
+
+#include <dpl/exception.h>
+
+namespace SecurityManager {
+
+class PrivilegeInfo {
+public:
+ class Exception {
+ public:
+ DECLARE_EXCEPTION_TYPE(SecurityManager::Exception, Base)
+ DECLARE_EXCEPTION_TYPE(Base, NotApplication)
+ DECLARE_EXCEPTION_TYPE(Base, InvalidAttribute)
+ DECLARE_EXCEPTION_TYPE(Base, UnknownError)
+ };
+
+ enum class PrivilegeAttr {
+ PRIVACY = 1,
+ BLACKLIST
+ };
+
+ PrivilegeInfo(uid_t uid, const std::string &label, const std::string &privilege);
+
+ bool hasAttribute(PrivilegeAttr attr);
+
+private:
+ uid_t m_uid;
+ std::string m_appId;
+ std::string m_pkgId;
+ std::string m_privilege;
+};
+
+} // namespace SecurityManager
+
+
static void setRequestDefaultValues(uid_t& uid, int& installationType);
- static void installRequestMangle(app_inst_req &req, std::string &cynaraUserStr);
-
bool authCheck(const Credentials &creds,
const uid_t &uid,
int installationType);
static bool isSharedRO(const pkg_paths& paths);
- static bool isPrivilegePrivacy(const std::string &clientLabel, const std::string &privilege);
-
int squashDropPrivateSharing(const std::string &ownerAppName,
const std::string &targetAppName,
const std::string &path);
--- /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 privilege-info.cpp
+ * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version 1.0
+ */
+
+#include <privilege_info.h> // external privilege-info header
+
+#include "privilege-info.h" // header for this file
+
+#include <dpl/log/log.h>
+#include <smack-labels.h>
+
+namespace SecurityManager {
+
+PrivilegeInfo::PrivilegeInfo(uid_t uid, const std::string &label, const std::string &privilege) :
+ m_uid(uid),
+ m_privilege(privilege)
+{
+ try {
+ SmackLabels::generateAppPkgNameFromLabel(label, m_appId, m_pkgId);
+ } catch(const SmackException::InvalidLabel&) {
+ LogDebug("Not an application label " << label);
+ ThrowMsg(Exception::NotApplication, "Not an application label");
+ }
+}
+
+bool PrivilegeInfo::hasAttribute(PrivilegeAttr attr)
+{
+ privilege_manager_privilege_type_e type;
+ int ret = privilege_info_get_privilege_type(m_uid, m_pkgId.c_str(), m_privilege.c_str(), &type);
+ if (ret != PRVMGR_ERR_NONE)
+ ThrowMsg(Exception::UnknownError, "Error while getting privilege type " << ret);
+
+ switch (attr) {
+ case PrivilegeAttr::PRIVACY:
+ return (type == PRIVILEGE_MANAGER_PRIVILEGE_TYPE_PRIVACY);
+ case PrivilegeAttr::BLACKLIST:
+ return (type == PRIVILEGE_MANAGER_PRIVILEGE_TYPE_BLACKLIST);
+ default:
+ ThrowMsg(Exception::InvalidAttribute, "Invalid privilege attribute " << static_cast<int>(attr));
+ }
+}
+
+} // namespace SecurityManager
+
#include <dpl/log/log.h>
#include <dpl/errno_string.h>
-#include <privilege_info.h>
#include <sys/smack.h>
#include <config.h>
#include "security-manager.h"
#include "tzplatform-config.h"
#include "utils.h"
+#include "privilege-info.h"
#include "service_impl.h"
uid = globalUid;
}
-void ServiceImpl::installRequestMangle(app_inst_req &req, std::string &cynaraUserStr)
-{
- setRequestDefaultValues(req.uid, req.installationType);
-
- if (req.installationType == SM_APP_INSTALL_GLOBAL
- || req.installationType == SM_APP_INSTALL_PRELOADED) {
- LogDebug("Installation type: global installation");
- cynaraUserStr = CYNARA_ADMIN_WILDCARD;
- } else if (req.installationType == SM_APP_INSTALL_LOCAL) {
- LogDebug("Installation type: local installation");
- cynaraUserStr = std::to_string(static_cast<unsigned int>(req.uid));
- } else
- LogError("Installation type: unknown");
-}
-
bool ServiceImpl::authCheck(const Credentials &creds,
const uid_t& uid,
int installationType)
}
}
-bool ServiceImpl::isPrivilegePrivacy(const std::string &clientLabel, const std::string &privilege)
-{
- int ret = privilege_info_is_privacy2(clientLabel.c_str(), privilege.c_str());
- if (ret == 1)
- return true;
- if (ret != 0)
- LogError("privilege_info_is_privacy called with " << privilege << " returned error: " << ret);
- // FIXME: we should probably disallow such installation where privilege is not known
- // However, currently privielge-checker seems to return -1 with so many real privileges
- // that it would make ask-user testing impossible.
- return false;
-}
-
bool ServiceImpl::isSharedRO(const pkg_paths& paths)
{
for (const auto& pkgPath : paths) {
bool hasSharedRO = isSharedRO(req.pkgPaths);
try {
- installRequestMangle(req, cynaraUserStr);
+ setRequestDefaultValues(req.uid, req.installationType);
LogDebug("Install parameters: appName: " << req.appName << ", pkgName: " << req.pkgName
<< ", uid: " << req.uid << ", target Tizen API ver: "
/* Get all application ids in the package to generate rules withing the package */
getPkgLabels(req.pkgName, pkgLabels);
m_priviligeDb.GetPkgAuthorId(req.pkgName, authorId);
- m_cynaraAdmin.UpdateAppPolicy(appLabel, cynaraUserStr, req.privileges, isPrivilegePrivacy);
+
+ bool global = req.installationType == SM_APP_INSTALL_GLOBAL ||
+ req.installationType == SM_APP_INSTALL_PRELOADED;
+ m_cynaraAdmin.UpdateAppPolicy(appLabel, global, req.uid, req.privileges);
if (hasSharedRO)
m_priviligeDb.SetSharedROPackage(req.pkgName);
} catch (const CynaraException::Base &e) {
LogError("Error while setting Cynara rules for application: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+ } catch (const PrivilegeInfo::Exception::Base &e) {
+ m_priviligeDb.RollbackTransaction();
+ LogError("Error while getting privilege information: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_SERVER_ERROR;
} catch (const PermissibleSet::PermissibleSetException::Base &e) {
LogError("Error while updating permissible file: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
bool isPkgHybrid;
std::vector<PkgInfo> pkgsInfo;
- installRequestMangle(req, cynaraUserStr);
+ setRequestDefaultValues(req.uid, req.installationType);
LogDebug("Uninstall parameters: appName=" << req.appName << ", uid=" << req.uid);
m_priviligeDb.GetPackagesInfo(pkgsInfo);
getPkgsProcessLabels(pkgsInfo, pkgsProcessLabels);
- m_cynaraAdmin.UpdateAppPolicy(processLabel, cynaraUserStr,
- std::vector<std::string>(), isPrivilegePrivacy);
+ bool global = req.installationType == SM_APP_INSTALL_GLOBAL ||
+ req.installationType == SM_APP_INSTALL_PRELOADED;
+ m_cynaraAdmin.UpdateAppPolicy(processLabel, global, req.uid, std::vector<std::string>());
trans.commit();
+
LogDebug("Application uninstallation commited to database");
updatePermissibleSet(req.uid, req.installationType);
} catch (const PrivilegeDb::Exception::IOError &e) {
} catch (const PrivilegeDb::Exception::Base &e) {
LogError("Error while removing application info from database: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+ } catch (const PrivilegeInfo::Exception::Base &e) {
+ m_priviligeDb.RollbackTransaction();
+ LogError("Error while getting privilege information: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_SERVER_ERROR;
} catch (const CynaraException::Base &e) {
LogError("Error while setting Cynara rules for application: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
}
try {
- m_cynaraAdmin.UserInit(uidAdded, static_cast<security_manager_user_type>(userType), isPrivilegePrivacy);
+ m_cynaraAdmin.UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
PermissibleSet::initializeUserPermissibleFile(uidAdded);
} catch (CynaraException::InvalidParam &e) {
return SECURITY_MANAGER_ERROR_INPUT_PARAM;
} catch (const SmackException::FileError &e) {
LogError("Error while adding user: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SETTING_FILE_LABEL_FAILED;
+ } catch (const PrivilegeInfo::Exception::Base &e) {
+ LogError("Error while getting privilege information: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_SERVER_ERROR;
} catch (const std::exception &e) {
LogError("Memory allocation error while adding user: " << e.what());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;