Add proper policy setup for privacy-related privileges 68/72568/9
authorTomasz Swierczek <t.swierczek@samsung.com>
Wed, 1 Jun 2016 13:44:47 +0000 (15:44 +0200)
committerTomasz Swierczek <t.swierczek@samsung.com>
Fri, 10 Jun 2016 13:38:16 +0000 (15:38 +0200)
Thanks to privielge-checker module API we can setup
"ASK-USER"/popup Cynara policy for privacy-related privileges.

Test with https://review.tizen.org/gerrit/#/c/72604/

Change-Id: I6bb8bc1dffc1e607c09b7722c6fac33b29620b4e

packaging/security-manager.spec
src/common/CMakeLists.txt
src/common/config.cpp
src/common/cynara.cpp
src/common/include/config.h
src/common/include/cynara.h
src/common/include/service_impl.h
src/common/service_impl.cpp

index 7ac305c..20a84bd 100644 (file)
@@ -25,6 +25,7 @@ BuildRequires: pkgconfig(sqlite3)
 BuildRequires: pkgconfig(db-util)
 BuildRequires: pkgconfig(cynara-admin)
 BuildRequires: pkgconfig(cynara-client-async)
+BuildRequires: pkgconfig(security-privilege-manager)
 BuildRequires: boost-devel
 %{?systemd_requires}
 
index fcfb46b..7c10f7b 100644 (file)
@@ -9,6 +9,7 @@ PKG_CHECK_MODULES(COMMON_DEP
     cynara-admin
     cynara-client-async
     libtzplatform-config
+    security-privilege-manager
     )
 
 IF(DPL_WITH_DLOG)
index 6b1887d..8c8dd9e 100644 (file)
@@ -45,6 +45,8 @@ const std::string PRIVILEGE_APPSHARING_ADMIN = "http://tizen.org/privilege/notex
 
 const std::string APPS_NAME_FILE = "apps-names";
 const std::string SKEL_DIR = "/etc/skel";
+
+const std::string PRIVACY_POLICY_DESC = "Ask user";
 };
 
 } /* namespace SecurityManager */
index d08f7d4..d2c26d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2014-2016 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -27,6 +27,7 @@
 
 #include <dpl/log/log.h>
 #include <dpl/errno_string.h>
+#include <config.h>
 
 namespace SecurityManager {
 
@@ -113,7 +114,6 @@ CynaraAdmin::BucketsMap CynaraAdmin::Buckets =
     { Bucket::MANIFESTS, std::string("MANIFESTS")},
 };
 
-
 CynaraAdminPolicy::CynaraAdminPolicy(const std::string &client, const std::string &user,
         const std::string &privilege, int operation,
         const std::string &bucket)
@@ -288,37 +288,74 @@ void CynaraAdmin::SetPolicies(const std::vector<CynaraAdminPolicy> &policies)
 void CynaraAdmin::UpdateAppPolicy(
     const std::string &label,
     const std::string &user,
-    const std::vector<std::string> &privileges)
-{
-    std::unordered_set<std::string> privilegesSet(privileges.begin(), privileges.end());
-
-    std::vector<CynaraAdminPolicy> policies;
-    CynaraAdmin::getInstance().ListPolicies(
-        CynaraAdmin::Buckets.at(Bucket::MANIFESTS),
-        label, user, CYNARA_ADMIN_ANY, policies);
+    const std::vector<std::string> &privileges,
+    std::function <bool(const std::string &)> isPrivacy)
+{
+    auto calcPolicies = [&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());
+        CynaraAdmin::getInstance().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));
+        }
 
-    // Compare previous policies with set of new requested privileges
-    for (auto &policy : policies) {
-        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);
+        // 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 << ") " <<
-                "removing privilege " << policy.privilege);
+                     "adding privilege " << privilege);
+            policies.push_back(CynaraAdminPolicy(label, user, privilege, policyToSet, bucket));
         }
-    }
+    };
 
-    // 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,
-                    static_cast<int>(CynaraAdminPolicy::Operation::Allow),
-                    Buckets.at(Bucket::MANIFESTS)));
+    std::vector<CynaraAdminPolicy> policies;
+
+    // 1st, performing operation on MANIFESTS bucket
+    calcPolicies(user, privileges, Buckets.at(Bucket::MANIFESTS),
+        static_cast<int>(CynaraAdminPolicy::Operation::Allow),
+        policies);
+
+    int askUserPolicy = convertToPolicyType(Config::PRIVACY_POLICY_DESC);
+
+    std::vector<std::string> privacyPrivileges;
+    for (auto &p : privileges)
+        if (isPrivacy(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);
     }
 
     SetPolicies(policies);
@@ -339,10 +376,12 @@ void CynaraAdmin::GetAppPolicy(const std::string &label, const std::string &user
     }
 }
 
-void CynaraAdmin::UserInit(uid_t uid, security_manager_user_type userType)
+void CynaraAdmin::UserInit(uid_t uid, security_manager_user_type userType,
+        std::function <bool(const std::string &)> isPrivacy)
 {
     Bucket bucket;
     std::vector<CynaraAdminPolicy> policies;
+    std::string userStr = std::to_string(uid);
 
     switch (userType) {
         case SM_USER_TYPE_SYSTEM:
@@ -365,11 +404,28 @@ void CynaraAdmin::UserInit(uid_t uid, security_manager_user_type userType)
     }
 
     policies.push_back(CynaraAdminPolicy(CYNARA_ADMIN_WILDCARD,
-                                            std::to_string(static_cast<unsigned int>(uid)),
+                                            userStr,
                                             CYNARA_ADMIN_WILDCARD,
                                             Buckets.at(bucket),
                                             Buckets.at(Bucket::MAIN)));
 
+    // 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;
+    CynaraAdmin::getInstance().ListPolicies(CynaraAdmin::Buckets.at(Bucket::MANIFESTS),
+                                            CYNARA_ADMIN_ANY, CYNARA_ADMIN_WILDCARD,
+                                            CYNARA_ADMIN_ANY, appPolicies);
+
+    for (CynaraAdminPolicy &policy : appPolicies)
+        if (isPrivacy(policy.privilege))
+            policies.push_back(CynaraAdminPolicy(policy.client,
+                userStr,
+                policy.privilege,
+                askUserPolicy,
+                Buckets.at(Bucket::PRIVACY_MANAGER)));
+
     CynaraAdmin::getInstance().SetPolicies(policies);
 }
 
index 9f4c466..01d0f79 100644 (file)
@@ -41,10 +41,13 @@ extern const std::string PRIVILEGE_POLICY_USER;
 extern const std::string PRIVILEGE_POLICY_ADMIN;
 extern const std::string PRIVILEGE_APPSHARING_ADMIN;
 
-/* Files used in permitted label managment*/
+/* Files used in permitted label managment */
 extern const std::string APPS_NAME_FILE;
 
 extern const std::string SKEL_DIR;
+
+/* Ask-user policy description */
+extern const std::string PRIVACY_POLICY_DESC;
 };
 
 } /* namespace SecurityManager */
index 219667d..1d267d4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2014-2016 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -33,6 +33,7 @@
 #include <mutex>
 #include <thread>
 #include <future>
+#include <functional>
 
 #include <poll.h>
 #include <sys/eventfd.h>
@@ -126,10 +127,11 @@ public:
      * @param label application Smack label
      * @param user 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);
+        const std::vector<std::string> &privileges,
+        std::function <bool(const std::string &)> isPrivacy);
 
     /**
      * Fetch Cynara policies for the application and the user.
@@ -150,8 +152,10 @@ public:
      *
      * @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);
+    void UserInit(uid_t uid, security_manager_user_type userType,
+        std::function <bool(const std::string &)> isPrivacy);
 
     /**
      * List all users registered in Cynara
index fbe6c5b..652244a 100644 (file)
@@ -72,6 +72,8 @@ private:
 
     static void getTizen2XApps(SmackRules::PkgsApps &pkgsApps);
 
+    static bool isPrivilegePrivacy(const std::string &privilege);
+
     int dropOnePrivateSharing(const std::string &ownerAppName,
                               const std::string &ownerPkgName,
                               const std::vector<std::string> &ownerPkgContents,
index b8ffc8a..583d23f 100644 (file)
@@ -35,6 +35,8 @@
 #include <dpl/log/log.h>
 #include <dpl/errno_string.h>
 
+#include <privilege_info.h>
+
 #include <config.h>
 #include "protocols.h"
 #include "privilege_db.h"
@@ -398,6 +400,19 @@ void ServiceImpl::getTizen2XApps(SmackRules::PkgsApps &pkgsApps)
     }
 }
 
+bool ServiceImpl::isPrivilegePrivacy(const std::string &privilege)
+{
+    int ret = privilege_info_is_privacy(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;
+}
+
 int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
 {
     std::vector<std::string> addedPermissions;
@@ -442,8 +457,7 @@ int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
         /* Get all application ids in the package to generate rules withing the package */
         PrivilegeDb::getInstance().GetPkgApps(req.pkgName, pkgContents);
         PrivilegeDb::getInstance().GetPkgAuthorId(req.pkgName, authorId);
-        CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, cynaraUserStr, req.privileges);
-
+        CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, cynaraUserStr, req.privileges, isPrivilegePrivacy);
         // if app is targetted to Tizen 2.X, give other 2.X apps RO rules to it's shared dir
         if (isTizen2XVersion(req.tizenVersion))
             getTizen2XApps(tizen2XpkgsApps);
@@ -563,7 +577,8 @@ int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &&req)
         if (isTizen2XVersion(req.tizenVersion))
             getTizen2XApps(tizen2XpkgsApps);
 
-        CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, cynaraUserStr, std::vector<std::string>());
+        CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, cynaraUserStr, std::vector<std::string>(), isPrivilegePrivacy);
+
         PrivilegeDb::getInstance().CommitTransaction();
         LogDebug("Application uninstallation commited to database");
         PermissibleSet::updatePermissibleFile(req.uid, req.installationType);
@@ -713,7 +728,8 @@ int ServiceImpl::userAdd(const Credentials &creds, uid_t uidAdded, int userType)
     }
 
     try {
-        CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
+        CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType), isPrivilegePrivacy);
+
     } catch (CynaraException::InvalidParam &e) {
         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
     }