Set Cynara policies during application installation and uninstallation 16/24416/9
authorRafal Krypa <r.krypa@samsung.com>
Sun, 13 Jul 2014 22:21:26 +0000 (00:21 +0200)
committerRafal Krypa <r.krypa@samsung.com>
Fri, 1 Aug 2014 12:17:41 +0000 (14:17 +0200)
Applied policies will have a wildcard in "user" field. Security-manager
will handle app installation per user soon, so this will also be changed.

Change-Id: I41606fb94b7385426debbcf47a57ba1593dbfc5a
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
Signed-off-by: Jan Cybulski <j.cybulski@samsung.com>
src/server/db/include/privilege_db.h
src/server/service/cynara.cpp
src/server/service/include/cynara.h
src/server/service/installer.cpp

index 7890022..b508576 100644 (file)
@@ -61,7 +61,7 @@ class PrivilegeDb {
 private:
     SecurityManager::DB::SqlConnection *mSqlConnection;
     const std::map<QueryType, const char * const > Queries = {
-        { QueryType::EGetPkgPrivileges, "SELECT privilege_name FROM app_privilege_view WHERE pkg_name=? AND uid=?"},
+        { QueryType::EGetPkgPrivileges, "SELECT DISTINCT privilege_name FROM app_privilege_view WHERE pkg_name=? AND uid=? ORDER BY privilege_name"},
         { QueryType::EAddApplication, "INSERT INTO app_pkg_view (app_name, pkg_name, uid) VALUES (?, ?, ?)" },
         { QueryType::ERemoveApplication, "DELETE FROM app_pkg_view WHERE app_name=? AND uid=?" },
         { QueryType::EAddAppPrivileges, "INSERT INTO app_privilege_view (app_name, uid, privilege_name) VALUES (?, ?, ?)" },
index 4925984..ab9dbf3 100644 (file)
@@ -26,6 +26,8 @@
 #include <vector>
 #include "cynara.h"
 
+#include <dpl/log/log.h>
+
 namespace SecurityManager {
 
 
@@ -133,8 +135,17 @@ void CynaraAdmin::SetPolicies(const std::vector<CynaraAdminPolicy> &policies)
 {
     std::vector<const struct cynara_admin_policy *> pp_policies(policies.size() + 1);
 
-    for (std::size_t i = 0; i < policies.size(); ++i)
+    LogDebug("Sending " << policies.size() << " policies to Cynara");
+    for (std::size_t i = 0; i < policies.size(); ++i) {
         pp_policies[i] = static_cast<const struct cynara_admin_policy *>(&policies[i]);
+        LogDebug("policies[" << i << "] = {" <<
+            ".bucket = " << pp_policies[i]->bucket << ", " <<
+            ".client = " << pp_policies[i]->client << ", " <<
+            ".user = " << pp_policies[i]->user << ", " <<
+            ".privilege = " << pp_policies[i]->privilege << ", " <<
+            ".result = " << pp_policies[i]->result << ", " <<
+            ".result_extra = " << pp_policies[i]->result_extra << "}");
+    }
 
     pp_policies[policies.size()] = nullptr;
 
@@ -143,4 +154,59 @@ void CynaraAdmin::SetPolicies(const std::vector<CynaraAdminPolicy> &policies)
         "Error while updating Cynara policy.");
 }
 
+void CynaraAdmin::UpdatePackagePolicy(
+    const std::string &pkg,
+    const std::string &user,
+    const std::vector<std::string> &oldPrivileges,
+    const std::vector<std::string> &newPrivileges)
+{
+    CynaraAdmin cynaraAdmin;
+    std::vector<CynaraAdminPolicy> policies;
+
+    // Perform sort-merge join on oldPrivileges and newPrivileges.
+    // Assume that they are already sorted and without duplicates.
+    auto oldIter = oldPrivileges.begin();
+    auto newIter = newPrivileges.begin();
+
+    while (oldIter != oldPrivileges.end() && newIter != newPrivileges.end()) {
+        int compare = oldIter->compare(*newIter);
+        if (compare == 0) {
+            LogDebug("(user = " << user << " pkg = " << pkg << ") " <<
+                "keeping privilege " << *newIter);
+            ++oldIter;
+            ++newIter;
+            continue;
+        } else if (compare < 0) {
+            LogDebug("(user = " << user << " pkg = " << pkg << ") " <<
+                "removing privilege " << *oldIter);
+            policies.push_back(CynaraAdminPolicy(pkg, user, *oldIter,
+                    CynaraAdminPolicy::Operation::Delete));
+            ++oldIter;
+        } else {
+            LogDebug("(user = " << user << " pkg = " << pkg << ") " <<
+                "adding privilege " << *newIter);
+            policies.push_back(CynaraAdminPolicy(pkg, user, *newIter,
+                    CynaraAdminPolicy::Operation::Allow));
+            ++newIter;
+        }
+    }
+
+    for (; oldIter != oldPrivileges.end(); ++oldIter) {
+        LogDebug("(user = " << user << " pkg = " << pkg << ") " <<
+            "removing privilege " << *oldIter);
+        policies.push_back(CynaraAdminPolicy(pkg, user, *oldIter,
+                    CynaraAdminPolicy::Operation::Delete));
+    }
+
+    for (; newIter != newPrivileges.end(); ++newIter) {
+        LogDebug("(user = " << user << " pkg = " << pkg << ") " <<
+            "adding privilege " << *newIter);
+        policies.push_back(CynaraAdminPolicy(pkg, user, *newIter,
+                    CynaraAdminPolicy::Operation::Allow));
+    }
+
+    cynaraAdmin.SetPolicies(policies);
+}
+
+
 } // namespace SecurityManager
index df28fdc..0daa1e5 100644 (file)
@@ -80,6 +80,28 @@ public:
      */
     void SetPolicies(const std::vector<CynaraAdminPolicy> &policies);
 
+    /**
+     * Update Cynara policies for the package and the user, using two vectors
+     * of privileges: privileges set before (and already enabled in Cynara)
+     * and new privileges, to be set in Cynara.
+     * Difference will be calculated, removing old unneeded privileges and
+     * adding new, previously not enabled privileges.
+     * Caller must have permission to access Cynara administrative socket.
+     *
+     * @param pkg package identifier
+     * @param user user identifier
+     * @param oldPrivileges previously enabled privileges for the package.
+     *        Must be sorted and without duplicates.
+     * @param newPrivileges currently enabled privileges for the package.
+     *        Must be sorted and without duplicates.
+     *
+     * TODO: drop oldPrivileges argument and get them directly from Cynara.
+     * Appropriate Cynara interface is needed first.
+     */
+    static void UpdatePackagePolicy(const std::string &pkg, const std::string &user,
+        const std::vector<std::string> &oldPrivileges,
+        const std::vector<std::string> &newPrivileges);
+
 private:
     struct cynara_admin *m_CynaraAdmin;
 };
index 286fce6..0e5ec01 100644 (file)
@@ -40,6 +40,7 @@
 #include "smack-rules.h"
 #include "smack-labels.h"
 #include "privilege_db.h"
+#include "cynara.h"
 
 namespace SecurityManager {
 
@@ -286,13 +287,23 @@ bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &s
         m_privilegeDb.AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
         m_privilegeDb.UpdateAppPrivileges(req.appId, uid, req.privileges);
         m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
-        // TODO: configure Cynara rules based on oldPkgPrivileges and newPkgPrivileges
+        CynaraAdmin::UpdatePackagePolicy(req.pkgId,
+                    CYNARA_ADMIN_WILDCARD, /* TODO: pass proper user identifier */
+                    oldPkgPrivileges, newPkgPrivileges);
         m_privilegeDb.CommitTransaction();
         LogDebug("Application installation commited to database");
     } catch (const PrivilegeDb::Exception::InternalError &e) {
         m_privilegeDb.RollbackTransaction();
         LogError("Error while saving application info to database: " << e.DumpToString());
         goto error_label;
+    } catch (const CynaraException::Base &e) {
+        m_privilegeDb.RollbackTransaction();
+        LogError("Error while setting Cynara rules for application: " << e.DumpToString());
+        goto error_label;
+    } catch (const std::bad_alloc &e) {
+        m_privilegeDb.RollbackTransaction();
+        LogError("Memory allocation while setting Cynara rules for application: " << e.what());
+        goto error_label;
     }
 
     // register paths
@@ -382,7 +393,9 @@ bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer
             m_privilegeDb.UpdateAppPrivileges(appId, uid, std::vector<std::string>());
             m_privilegeDb.RemoveApplication(appId, uid, removePkg);
             m_privilegeDb.GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
-            // TODO: configure Cynara rules based on oldPkgPrivileges and newPkgPrivileges
+            CynaraAdmin::UpdatePackagePolicy(pkgId,
+                            CYNARA_ADMIN_WILDCARD, /* TODO: pass proper user identifier */
+                            oldPkgPrivileges, newPkgPrivileges);
             m_privilegeDb.CommitTransaction();
             LogDebug("Application uninstallation commited to database");
         }
@@ -390,6 +403,14 @@ bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer
         m_privilegeDb.RollbackTransaction();
         LogError("Error while removing application info from database: " << e.DumpToString());
         goto error_label;
+    } catch (const CynaraException::Base &e) {
+        m_privilegeDb.RollbackTransaction();
+        LogError("Error while setting Cynara rules for application: " << e.DumpToString());
+        goto error_label;
+    } catch (const std::bad_alloc &e) {
+        m_privilegeDb.RollbackTransaction();
+        LogError("Memory allocation while setting Cynara rules for application: " << e.what());
+        goto error_label;
     }
 
     if (appExists) {