Implement security_manager_prepare_app_privacy 15/120915/7
authorRafal Krypa <r.krypa@samsung.com>
Fri, 31 Mar 2017 11:38:34 +0000 (13:38 +0200)
committerTomasz Swierczek <t.swierczek@samsung.com>
Sun, 2 Apr 2017 12:31:16 +0000 (14:31 +0200)
Change-Id: I9467a359672f5a1e3147a92ae2eb282a1e643b26
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
12 files changed:
packaging/security-manager.spec
src/client/CMakeLists.txt
src/client/client-security-manager.cpp
src/common/cynara.cpp
src/common/include/cynara.h
src/common/include/privilege-info.h
src/common/include/protocols.h
src/common/include/service_impl.h
src/common/privilege-info.cpp
src/common/service_impl.cpp
src/server/service/include/service.h
src/server/service/service.cpp

index 9e388adb26ae98e28d50b32e71a1844d0388f49c..025e90b5250ba0105d4b6fef94826c2db7e46b00 100644 (file)
@@ -33,6 +33,7 @@ BuildRequires: pkgconfig(db-util)
 BuildRequires: pkgconfig(cynara-admin)
 BuildRequires: pkgconfig(cynara-client-async)
 BuildRequires: pkgconfig(security-privilege-manager)
+BuildRequires: pkgconfig(askuser-notification-ipc)
 BuildRequires: boost-devel
 %{?systemd_requires}
 
index 9d56f05ee383226a28ab5571071533cbacb8deaf..ddbb352f0961886157c62d3dd740b7118cb0db6a 100644 (file)
@@ -4,6 +4,7 @@ PKG_CHECK_MODULES(CLIENT_DEP
     libsmack
     libcap
     libprocps
+    askuser-notification-ipc
     )
 
 SET(CLIENT_VERSION_MAJOR 2)
index 3a62fef9f4527cf721a0ff1bd902fca54bfe80a7..dff5c46705b9fbc02e32f3c1cdfa3d85a4ee85f7 100644 (file)
 #include <service_impl.h>
 #include <check-proper-drop.h>
 #include <utils.h>
+#include <privilege-info.h>
+#include <config.h>
 
 #include <security-manager.h>
 #include <client-offline.h>
 #include <dpl/errno_string.h>
+#include <askuser-notification/ask-user-client.h>
 
 #include "filesystem.h"
 
@@ -280,6 +283,16 @@ int security_manager_app_uninstall(const app_inst_req *p_req)
     });
 }
 
+static int getAppPkgName(std::string &pkgName, const std::string &appName)
+{
+    ClientRequest request(SecurityModuleCall::APP_GET_PKG_NAME);
+    if (request.send(appName).failed())
+        return request.getStatus();
+
+    request.recv(pkgName);
+    return SECURITY_MANAGER_SUCCESS;
+}
+
 SECURITY_MANAGER_API
 int security_manager_get_app_pkgid(char **pkg_name, const char *app_name)
 {
@@ -300,18 +313,17 @@ int security_manager_get_app_pkgid(char **pkg_name, const char *app_name)
             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
         }
 
-        ClientRequest request(SecurityModuleCall::APP_GET_PKG_NAME);
-        if (request.send(std::string(app_name)).failed())
-            return request.getStatus();
+        std::string pkgName;
+        int ret = getAppPkgName(pkgName, std::string(app_name));
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
 
-        std::string pkgNameString;
-        request.recv(pkgNameString);
-        if (pkgNameString.empty()) {
+        if (pkgName.empty()) {
             LogError("Unexpected empty pkgName");
             return SECURITY_MANAGER_ERROR_UNKNOWN;
         }
 
-        *pkg_name = strdup(pkgNameString.c_str());
+        *pkg_name = strdup(pkgName.c_str());
         if (*pkg_name == NULL) {
             LogError("Failed to allocate memory for pkgName");
             return SECURITY_MANAGER_ERROR_MEMORY;
@@ -1573,17 +1585,187 @@ int security_manager_shm_open(const char *name, int oflag, mode_t mode, const ch
     });
 }
 
+static int getAppPrivacy(const std::string &appName,
+    std::vector<std::string> &privacyAsk, std::vector<std::string> &privacyDeny)
+{
+    using namespace SecurityManager;
+
+    ClientRequest request(SecurityModuleCall::APP_GET_PRIVACY);
+    if (request.send(appName).failed())
+        return request.getStatus();
+
+    request.recv(privacyAsk);
+    request.recv(privacyDeny);
+    return SECURITY_MANAGER_SUCCESS;
+}
+
+static int updateAppPrivacy(const std::string &appName,
+    const std::vector<std::string> &privacy, const std::string &policy)
+{
+    using namespace SecurityManager;
+
+    class privacyUpdateRequest {
+    public:
+        int init()
+        {
+            return security_manager_policy_update_req_new(&m_req);
+        };
+
+        int add(const std::string &appName, const std::string &privilege,
+            const std::string &policy)
+        {
+            int ret;
+            policy_entry *entry = nullptr;
+
+            ret = security_manager_policy_entry_new(&entry);
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                return ret;
+            m_entries.push_back(entry);
+
+            ret = security_manager_policy_entry_set_application(entry, appName.c_str());
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                return ret;
+
+            ret = security_manager_policy_entry_set_privilege(entry, privilege.c_str());
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                return ret;
+
+            ret = security_manager_policy_entry_set_level(entry, policy.c_str());
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                return ret;
+
+            ret = security_manager_policy_update_req_add_entry(m_req, entry);
+            if (ret != SECURITY_MANAGER_SUCCESS)
+                return ret;
+
+            return SECURITY_MANAGER_SUCCESS;
+        };
+
+        int send()
+        {
+            return security_manager_policy_update_send(m_req);
+        }
+
+        ~privacyUpdateRequest()
+        {
+            for (policy_entry *entry : m_entries)
+                security_manager_policy_entry_free(entry);
+            security_manager_policy_update_req_free(m_req);
+        };
+
+    private:
+        policy_update_req *m_req = nullptr;
+        std::vector<policy_entry *> m_entries;
+    };
+
+    int ret;
+    privacyUpdateRequest pur;
+    ret = pur.init();
+    if (ret != SECURITY_MANAGER_SUCCESS)
+        return ret;
+
+    for (const std::string &privilege : privacy) {
+        ret = pur.add(appName, privilege, policy);
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+    }
+
+    return pur.send();
+}
+
 SECURITY_MANAGER_API
 int security_manager_prepare_app_privacy(const char *app_name)
 {
     using namespace SecurityManager;
+
     return try_catch([&]() -> int {
         if (app_name == nullptr) {
             LogError("app_name is NULL");
             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
         }
 
-        // TODO: stub implementation
-        return SECURITY_MANAGER_ERROR_UNKNOWN;
+        int ret;
+        std::string pkgName;
+        ret = getAppPkgName(pkgName, std::string(app_name));
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+
+        std::vector<std::string> privacyAsk;
+        std::vector<std::string> privacyDeny;
+        ret = getAppPrivacy(app_name, privacyAsk, privacyDeny);
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+
+        if (privacyAsk.empty()) {
+            if (privacyDeny.empty())
+                return SECURITY_MANAGER_SUCCESS;
+
+            if (PrivilegeInfo::isAppWhiteListed(pkgName))
+                return SECURITY_MANAGER_SUCCESS;
+
+            AskUser::Protocol::toast_fail_launch(pkgName, app_name, getuid());
+            return SECURITY_MANAGER_ERROR_APP_LAUNCH_PROHIBITED;
+        }
+
+        std::sort(privacyAsk.begin(), privacyAsk.end());
+        std::sort(privacyDeny.begin(), privacyDeny.end());
+
+        std::vector<std::string> privacy;
+        std::merge(
+            privacyAsk.begin(), privacyAsk.end(),
+            privacyDeny.begin(), privacyDeny.end(),
+            std::back_inserter(privacy));
+
+        int askResult;
+        if (AskUser::Protocol::popup_launch(pkgName, app_name, getuid(), privacy, askResult) < 0) {
+            LogError("Launch pop-up failed");
+            return SECURITY_MANAGER_ERROR_UNKNOWN;
+        }
+
+        bool launchAllowed;
+        switch (askResult) {
+        case ASKUSER_DENY_ONCE:
+            LogDebug("Launch pop-up response: deny once");
+            launchAllowed = false;
+            ret = SECURITY_MANAGER_SUCCESS;
+            break;
+
+        case ASKUSER_DENY_FOREVER:
+            LogDebug("Launch pop-up response: deny forever");
+            launchAllowed = false;
+            ret = updateAppPrivacy(app_name, privacy, Config::PRIVACY_POLICY_DENY);
+            break;
+
+        case ASKUSER_ALLOW_ONCE:
+            LogDebug("Launch pop-up response: allow once");
+            launchAllowed = true;
+            ret = SECURITY_MANAGER_SUCCESS;
+            break;
+
+        case ASKUSER_ALLOW_FOREVER:
+            LogDebug("Launch pop-up response: allow forever");
+            launchAllowed = true;
+            ret = updateAppPrivacy(app_name, privacy, Config::PRIVACY_POLICY_ALLOW);
+            break;
+
+        default:
+            LogError("Launch pop-up response: UNKNOWN");
+            return SECURITY_MANAGER_ERROR_UNKNOWN;
+        }
+
+        if (ret != SECURITY_MANAGER_SUCCESS)
+            return ret;
+
+        if (launchAllowed)
+            return SECURITY_MANAGER_SUCCESS;
+
+        if (PrivilegeInfo::isAppWhiteListed(pkgName)) {
+            LogInfo("Launch pop-up denied privileges, whitelisted app - launching");
+            return SECURITY_MANAGER_SUCCESS;
+        }
+
+        LogInfo("Launch pop-up denied privileges, whitelisted app - not launching");
+        AskUser::Protocol::toast_fail_launch(pkgName, app_name, getuid());
+        return SECURITY_MANAGER_ERROR_APP_LAUNCH_PROHIBITED;
     });
 }
index 42742b52a082bf3e8d904f8b9e078998ec7be6d7..2b3215b24ab8963fa29aeb0a48d29b23b22cfb38 100644 (file)
@@ -390,6 +390,24 @@ void CynaraAdmin::getAppPolicy(const std::string &label, const std::string &user
     }
 }
 
+void CynaraAdmin::getAppPrivacy(const std::string &label, const std::string &user,
+        std::vector<std::string> &privacyAsk, std::vector<std::string> &privacyDeny)
+{
+    privacyAsk.clear();
+    privacyDeny.clear();
+
+    std::vector<CynaraAdminPolicy> policies;
+    listPolicies(CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
+        label, user, CYNARA_ADMIN_ANY, policies);
+
+    for (const auto &policy : policies) {
+        if (policy.result == convertToPolicyType(Config::PRIVACY_POLICY_ASK))
+            privacyAsk.push_back(std::string(policy.privilege));
+        else if (policy.result == convertToPolicyType(Config::PRIVACY_POLICY_DENY))
+            privacyDeny.push_back(std::string(policy.privilege));
+    }
+}
+
 void CynaraAdmin::userInit(uid_t uid, security_manager_user_type userType)
 {
     Bucket bucket;
index ec2b4eb360da9fd392dbebd6e3119502dae1cc9b..638051bba4d382265f0111e2ba205cb2390250f7 100644 (file)
@@ -147,6 +147,18 @@ public:
     void getAppPolicy(const std::string &label, const std::string &user,
         std::vector<std::string> &privileges);
 
+    /**
+     * Fetch application privileges that are set to ASK_USER_LEGACY
+     * (launch pop-up needed) or PRIVACY_DENY (disabled)
+     *
+     * @param[in] label application Smack label
+     * @param[in] user user identifier
+     * @param[out] privacyAsk returned vector of privileges that are set to ASK_USER_LEGACY
+     * @param[out] privacyDeny returned vector of privileges that are set to PRIVACY_DENY
+     */
+    void getAppPrivacy(const std::string &label, const std::string &user,
+        std::vector<std::string> &privacyAsk, std::vector<std::string> &privacyDeny);
+
     /**
      * Depending on user type, create link between MAIN bucket and appropriate
      * USER_TYPE_* bucket for newly added user uid to apply permissions for that
index 64a3f5952bac0dc0a04793ba46932712d316a36e..90a537978ab98b92687390ea0bf4d4d5083ca69a 100644 (file)
@@ -47,6 +47,8 @@ public:
 
     bool hasAttribute(PrivilegeAttr attr);
 
+    static bool isAppWhiteListed(const std::string &pkgName);
+
 private:
     uid_t m_uid;
     std::string m_appId;
index fcf13141235dfbe9093b184cabd785102f04725b..e9a6d6beb5bf5298c735adffd86df5435cb250a2 100644 (file)
@@ -88,6 +88,7 @@ enum class SecurityModuleCall
     GROUPS_FOR_UID,
     LABEL_FOR_PROCESS,
     SHM_APP_NAME,
+    APP_GET_PRIVACY,
     NOOP = 0x90,
 };
 
index bc75e50c6518f5be44117b76406b50dafb15d723..87988a5b9a21a257d861c677fd494b2e0c59e0ba 100644 (file)
@@ -234,6 +234,7 @@ public:
      * @return API return code, as defined in protocols.h
      */
     int labelForProcess(const std::string &appName, std::string &label);
+
     /*
      * Request for access to shared memory segment for
      * appName application.
@@ -247,6 +248,23 @@ public:
     int shmAppName(const Credentials &creds,
                    const std::string &shmName,
                    const std::string &appName);
+
+    /*
+     * Fetch application privileges that are set to ASK_USER_LEGACY
+     * (launch pop-up needed) or PRIVACY_DENY (disabled)
+     *
+     * @param[in] creds credentials of the requesting process
+     * @param[in] appName application identifier
+     * @param[out] privacyAsk returned vector of privileges that are set to ASK_USER_LEGACY
+     * @param[out] privacyDeny returned vector of privileges that are set to PRIVACY_DENY
+     *
+     * @return API return code, as defined in protocols.h
+     */
+    int getAppPrivacy(const Credentials &creds,
+                      const std::string &appName,
+                      std::vector<std::string> &privacyAsk,
+                      std::vector<std::string> &privacyDeny);
+
 private:
     bool authenticate(const Credentials &creds, const std::string &privilege);
 
index 8df2c3d845fbffe12e73cb37afeba9adcab30f16..cb26a73b7c207d54042b186c787e360f8b0a686f 100644 (file)
@@ -57,5 +57,10 @@ bool PrivilegeInfo::hasAttribute(PrivilegeAttr attr)
     }
 }
 
+bool PrivilegeInfo::isAppWhiteListed(const std::string &pkgName)
+{
+    return privilege_info_is_privacy_white_list_application(pkgName.c_str());
+}
+
 } // namespace SecurityManager
 
index bec0060564a0fcce32e8fbdba05e6b8da0d81052..f459a897369b8c21a4774bca48ee7b369b910798 100644 (file)
@@ -1691,4 +1691,27 @@ int ServiceImpl::shmAppName(const Credentials &creds, const std::string &shmName
     return SECURITY_MANAGER_SUCCESS;
 }
 
+int ServiceImpl::getAppPrivacy(const Credentials &creds, const std::string &appName,
+                  std::vector<std::string> &privacyAsk,
+                  std::vector<std::string> &privacyDeny)
+{
+    try {
+        std::string uidStr = std::to_string(creds.uid);
+        std::string appProcessLabel = getAppProcessLabel(appName);
+        std::vector<std::string> privileges;
+        m_cynaraAdmin.getAppPrivacy(appProcessLabel, uidStr, privacyAsk, privacyDeny);
+    } catch (const CynaraException::Base &e) {
+        LogError("Error while reading Cynara policy: " << e.DumpToString());
+        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    } catch (const SmackException::Base &e) {
+        LogError("Error while generating Smack label: " << e.DumpToString());
+        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    } catch (const std::bad_alloc &e) {
+        LogError("Memory allocation failed: " << e.what());
+        return SECURITY_MANAGER_ERROR_MEMORY;
+    }
+
+    return SECURITY_MANAGER_SUCCESS;
+}
+
 } /* namespace SecurityManager */
index 90c8ed8d93bd596c1e55b71ba580eb828ce7e141..ba76ecb83258865043527c503202040da8a52cca 100644 (file)
@@ -202,6 +202,15 @@ private:
      * @param  creds  credentials of the requesting process
      */
     void processShmAppName(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds);
+
+    /**
+     * Process getting privacy privileges for application
+     *
+     * @param  recv   Raw received data buffer
+     * @param  send   Raw data buffer to be sent
+     * @param  creds  credentials of the requesting process
+     */
+    void processGetAppPrivacy(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds);
 };
 
 } // namespace SecurityManager
index fe4f865b99c5b190c424fe918ecd5d8e0d9fa548..f5563041905e7217f6b86341f101727aae80905c 100644 (file)
@@ -150,6 +150,9 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                 case SecurityModuleCall::SHM_APP_NAME:
                     processShmAppName(buffer, send, creds);
                     break;
+                case SecurityModuleCall::APP_GET_PRIVACY:
+                    processGetAppPrivacy(buffer, send, creds);
+                    break;
                 default:
                     LogError("Invalid call: " << call_type_int);
                     Throw(ServiceException::InvalidAction);
@@ -418,4 +421,19 @@ void Service::processShmAppName(MessageBuffer &recv, MessageBuffer &send, const
     Serialization::Serialize(send, ret);
 }
 
+void Service::processGetAppPrivacy(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds)
+{
+    std::string appName;
+    Deserialization::Deserialize(recv, appName);
+
+    std::vector<std::string> privacyAsk, privacyDeny;
+    int ret = serviceImpl.getAppPrivacy(creds, appName, privacyAsk, privacyDeny);
+    Serialization::Serialize(send, ret);
+    if (ret == SECURITY_MANAGER_SUCCESS) {
+        Serialization::Serialize(send, privacyAsk);
+        Serialization::Serialize(send, privacyDeny);
+    }
+}
+
+
 } // namespace SecurityManager