Add possibility of installing apps for different users 03/24703/8
authorJan Cybulski <j.cybulski@samsung.com>
Fri, 18 Jul 2014 15:35:41 +0000 (17:35 +0200)
committerJan Cybulski <j.cybulski@samsung.com>
Mon, 21 Jul 2014 06:44:24 +0000 (08:44 +0200)
Uid of installing user will be obtained from peer's socket
and will be stored in database.

Change-Id: I0a0edf726b54fc7b28e5f2063186a97eb29479a9
Signed-off-by: Jan Cybulski <j.cybulski@samsung.com>
src/server/db/db.sql
src/server/db/include/privilege_db.h
src/server/db/privilege_db.cpp
src/server/service/include/installer.h
src/server/service/installer.cpp

index 680c2ed..513a664 100644 (file)
@@ -15,8 +15,9 @@ UNIQUE (name)
 CREATE TABLE IF NOT EXISTS app (
 app_id INTEGER PRIMARY KEY,
 pkg_id INTEGER NOT NULL,
+uid INTEGER NOT NULL,
 name VARCHAR NOT NULL ,
-UNIQUE (name),
+UNIQUE (name, uid),
 FOREIGN KEY (pkg_id) REFERENCES pkg (pkg_id)
 );
 
@@ -46,6 +47,7 @@ CREATE VIEW app_privilege_view AS
 SELECT
        app_privilege.app_id as app_id,
        app.name as app_name,
+       app.uid as uid,
        app.pkg_id as pkg_id,
        pkg.name as pkg_name,
        app_privilege.privilege_id as privilege_id,
@@ -61,6 +63,7 @@ SELECT
     app.app_id,
     app.name as app_name,
     app.pkg_id,
+    app.uid,
     pkg.name as pkg_name
 FROM app
 LEFT JOIN pkg USING (pkg_id);
@@ -71,7 +74,7 @@ INSTEAD OF INSERT ON app_privilege_view
 BEGIN
        INSERT OR IGNORE INTO privilege(name) VALUES (NEW.privilege_name);
        INSERT OR IGNORE INTO app_privilege(app_id, privilege_id) VALUES
-               ((SELECT app_id FROM app WHERE name=NEW.app_name),
+               ((SELECT app_id FROM app WHERE name=NEW.app_name AND uid=NEW.uid),
                 (SELECT privilege_id FROM privilege WHERE name=NEW.privilege_name));
 END;
 
@@ -87,14 +90,14 @@ CREATE TRIGGER app_pkg_view_insert_trigger
 INSTEAD OF INSERT ON app_pkg_view
 BEGIN
     INSERT OR IGNORE INTO pkg(name) VALUES (NEW.pkg_name);
-    INSERT OR IGNORE INTO app(pkg_id, name) VALUES ((SELECT pkg_id FROM pkg WHERE name=NEW.pkg_name), NEW.app_name);
+    INSERT OR IGNORE INTO app(pkg_id, name, uid) VALUES ((SELECT pkg_id FROM pkg WHERE name=NEW.pkg_name), NEW.app_name, NEW.uid);
 END;
 
 DROP TRIGGER IF EXISTS app_pkg_view_delete_trigger;
 CREATE TRIGGER app_pkg_view_delete_trigger
 INSTEAD OF DELETE ON app_pkg_view
 BEGIN
-    DELETE FROM app WHERE app_id=OLD.app_id;
+    DELETE FROM app WHERE app_id=OLD.app_id AND uid=OLD.uid;
     DELETE FROM pkg WHERE pkg_id NOT IN (SELECT DISTINCT pkg_id from app);
 END;
 
index b90c1c0..7890022 100644 (file)
@@ -61,11 +61,11 @@ 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=?"},
-        { QueryType::EAddApplication, "INSERT INTO app_pkg_view (app_name, pkg_name) VALUES (?, ?)" },
-        { QueryType::ERemoveApplication, "DELETE FROM app_pkg_view WHERE app_name=?" },
-        { QueryType::EAddAppPrivileges, "INSERT INTO app_privilege_view (app_name, privilege_name) VALUES (?, ?)" },
-        { QueryType::ERemoveAppPrivileges, "DELETE FROM app_privilege_view WHERE app_name=?" },
+        { QueryType::EGetPkgPrivileges, "SELECT privilege_name FROM app_privilege_view WHERE pkg_name=? AND uid=?"},
+        { 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 (?, ?, ?)" },
+        { QueryType::ERemoveAppPrivileges, "DELETE FROM app_privilege_view WHERE app_name=? AND uid=?" },
         { QueryType::EPkgIdExists, "SELECT * FROM pkg WHERE name=?" },
         { QueryType::EGetPkgId, " SELECT pkg_name FROM app_pkg_view WHERE app_name = ?" },
     };
@@ -133,10 +133,11 @@ public:
      * Retrieve list of privileges assigned to a pkgId
      *
      * @param pkgId - package identifier
+     * @param uid - user identifier for whom privileges will be retrieved
      * @param[out] currentPrivileges - list of current privileges assigned to pkgId
      * @exception DB::SqlConnection::Exception::InternalError on internal error
      */
-    void GetPkgPrivileges(const std::string &pkgId,
+    void GetPkgPrivileges(const std::string &pkgId, uid_t uid,
             std::vector<std::string> &currentPrivilege);
 
     /**
@@ -144,38 +145,42 @@ public:
      *
      * @param appId - application identifier
      * @param pkgId - package identifier
+     * @param uid - user identifier for whom application is going to be installed
      * @param[out] pkgIdIsNew - return info if pkgId is new to the database
      * @exception DB::SqlConnection::Exception::InternalError on internal error
      */
     void AddApplication(const std::string &appId, const std::string &pkgId,
-            bool &pkgIdIsNew);
+            uid_t uid, bool &pkgIdIsNew);
 
     /**
      * Remove an application from the database
      *
      * @param appId - application identifier
+     * @param uid - user identifier whose application is going to be uninstalled
      * @param[out] pkgIdIsNoMore - return info if pkgId is in the database
      * @exception DB::SqlConnection::Exception::InternalError on internal error
      */
-    void RemoveApplication(const std::string &appId, bool &pkgIdIsNoMore);
+    void RemoveApplication(const std::string &appId, uid_t uid, bool &pkgIdIsNoMore);
 
     /**
      * Remove privileges assigned to application
      *
      * @param appId - application identifier
+     * @param uid - user identifier for whom privileges will be removed
      * @exception DB::SqlConnection::Exception::InternalError on internal error
      */
-    void RemoveAppPrivileges(const std::string &appId);
+    void RemoveAppPrivileges(const std::string &appId, uid_t uid);
 
     /**
      * Update privileges assigned to application
      * To assure data integrity this method must be called inside db transaction.
      *
      * @param appId - application identifier
+     * @param uid - user identifier for whom privileges will be updated
      * @param privileges - list of privileges to assign
      * @exception DB::SqlConnection::Exception::InternalError on internal error
      */
-    void UpdateAppPrivileges(const std::string &appId,
+    void UpdateAppPrivileges(const std::string &appId, uid_t uid,
             const std::vector<std::string> &privileges);
 
 };
index 5eafde6..32e18b4 100644 (file)
@@ -132,7 +132,7 @@ bool PrivilegeDb::GetAppPkgId(const std::string &appId, std::string &pkgId)
 }
 
 void PrivilegeDb::AddApplication(const std::string &appId,
-        const std::string &pkgId, bool &pkgIdIsNew)
+        const std::string &pkgId, uid_t uid, bool &pkgIdIsNew)
 {
     pkgIdIsNew = !(this->PkgIdExists(pkgId));
 
@@ -143,6 +143,7 @@ void PrivilegeDb::AddApplication(const std::string &appId,
 
         command->BindString(1, appId.c_str());
         command->BindString(2, pkgId.c_str());
+        command->BindInteger(3, static_cast<unsigned int>(uid));
 
         if (command->Step()) {
             LogDebug("Unexpected SQLITE_ROW answer to query: " <<
@@ -154,7 +155,7 @@ void PrivilegeDb::AddApplication(const std::string &appId,
     });
 }
 
-void PrivilegeDb::RemoveApplication(const std::string &appId,
+void PrivilegeDb::RemoveApplication(const std::string &appId, uid_t uid,
         bool &pkgIdIsNoMore)
 {
     try_catch<void>([&] {
@@ -169,6 +170,7 @@ void PrivilegeDb::RemoveApplication(const std::string &appId,
                         Queries.at(QueryType::ERemoveApplication));
 
         command->BindString(1, appId.c_str());
+        command->BindInteger(2, static_cast<unsigned int>(uid));
 
         if (command->Step()) {
             LogDebug("Unexpected SQLITE_ROW answer to query: " <<
@@ -182,7 +184,7 @@ void PrivilegeDb::RemoveApplication(const std::string &appId,
     });
 }
 
-void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId,
+void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId, uid_t uid,
         std::vector<std::string> &currentPrivileges)
 {
     try_catch<void>([&] {
@@ -190,6 +192,7 @@ void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId,
                 mSqlConnection->PrepareDataCommand(
                         Queries.at(QueryType::EGetPkgPrivileges));
         command->BindString(1, pkgId.c_str());
+        command->BindInteger(2, static_cast<unsigned int>(uid));
 
         while (command->Step()) {
             std::string privilege = command->GetColumnString(0);
@@ -199,13 +202,14 @@ void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId,
     });
 }
 
-void PrivilegeDb::RemoveAppPrivileges(const std::string &appId)
+void PrivilegeDb::RemoveAppPrivileges(const std::string &appId, uid_t uid)
 {
     try_catch<void>([&] {
         DB::SqlConnection::DataCommandAutoPtr command =
             mSqlConnection->PrepareDataCommand(Queries.at(QueryType::ERemoveAppPrivileges));
 
         command->BindString(1, appId.c_str());
+        command->BindInteger(2, static_cast<unsigned int>(uid));
         if (command->Step()) {
             LogDebug("Unexpected SQLITE_ROW answer to query: " <<
                     Queries.at(QueryType::ERemoveAppPrivileges));
@@ -215,18 +219,19 @@ void PrivilegeDb::RemoveAppPrivileges(const std::string &appId)
     });
 }
 
-void PrivilegeDb::UpdateAppPrivileges(const std::string &appId,
+void PrivilegeDb::UpdateAppPrivileges(const std::string &appId, uid_t uid,
         const std::vector<std::string> &privileges)
 {
     try_catch<void>([&] {
         DB::SqlConnection::DataCommandAutoPtr command =
             mSqlConnection->PrepareDataCommand(Queries.at(QueryType::EAddAppPrivileges));
         command->BindString(1, appId.c_str());
+        command->BindInteger(2, static_cast<unsigned int>(uid));
 
-        RemoveAppPrivileges(appId);
+        RemoveAppPrivileges(appId, uid);
 
         for (const auto &privilege : privileges) {
-            command->BindString(2, privilege.c_str());
+            command->BindString(3, privilege.c_str());
             command->Step();
             command->Reset();
             LogDebug("Added privilege: " << privilege << " to appId: " << appId);
index c1f8d42..1a7caf2 100644 (file)
@@ -77,18 +77,20 @@ private:
      *
      * @param  buffer Raw received data buffer
      * @param  send   Raw data buffer to be sent
+     * @param  uid    User's identifier for whom application will be installed
      * @return        true on success
      */
-    bool processAppInstall(MessageBuffer &buffer, MessageBuffer &send);
+    bool processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid);
 
     /**
-     * Process libprivilege-control action and store result in a bufer
+     * Process application uninstallation
      *
      * @param  buffer Raw received data buffer
      * @param  send   Raw data buffer to be sent
+     * @param  uid    User's identifier for whom application will be uninstalled
      * @return        true on success
      */
-    bool processAppUninstall(MessageBuffer &buffer, MessageBuffer &send);
+    bool processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid);
 
     /**
      * Process getting package id from app id
index 8f7bb0c..6451dc8 100644 (file)
@@ -27,6 +27,8 @@
 #include <dpl/serialization.h>
 
 #include <privilege-control.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 
 #include "installer.h"
 #include "protocols.h"
@@ -89,6 +91,19 @@ void InstallerService::close(const CloseEvent &event)
     m_connectionInfoMap.erase(event.connectionID.counter);
 }
 
+static bool getPeerUserID(int sock, uid_t *uid) {
+    struct ucred cr;
+    socklen_t len = sizeof (cr);
+    if (!uid) {
+        return false;
+    }
+    if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) {
+        *uid = cr.uid;
+        return true;
+    }
+    return false;
+}
+
 bool InstallerService::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                                   InterfaceID interfaceID)
 {
@@ -102,6 +117,14 @@ bool InstallerService::processOne(const ConnectionID &conn, MessageBuffer &buffe
     MessageBuffer send;
     bool retval = false;
 
+    uid_t uid;
+
+    if(!getPeerUserID(conn.sock, &uid)) {
+        LogError("Closing socket because of error: unable to get peer's uid");
+        m_serviceManager->Close(conn);
+        return false;
+    }
+
     if (INSTALLER_IFACE == interfaceID) {
         Try {
             // deserialize API call type
@@ -112,11 +135,11 @@ bool InstallerService::processOne(const ConnectionID &conn, MessageBuffer &buffe
             switch (call_type) {
                 case SecurityModuleCall::APP_INSTALL:
                     LogDebug("call_type: SecurityModuleCall::APP_INSTALL");
-                    processAppInstall(buffer, send);
+                    processAppInstall(buffer, send, uid);
                     break;
                 case SecurityModuleCall::APP_UNINSTALL:
                     LogDebug("call_type: SecurityModuleCall::APP_UNINSTALL");
-                    processAppUninstall(buffer, send);
+                    processAppUninstall(buffer, send, uid);
                     break;
                 case SecurityModuleCall::APP_GET_PKGID:
                     processGetPkgId(buffer, send);
@@ -152,7 +175,19 @@ bool InstallerService::processOne(const ConnectionID &conn, MessageBuffer &buffe
     return retval;
 }
 
-bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &send)
+static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid)
+{
+    for (const auto &appPath : req.appPaths) {
+        app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
+        if (pathType == SECURITY_MANAGER_PATH_PUBLIC && uid != 0) {
+            LogDebug("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
+            return false;
+        }
+    }
+    return true;
+}
+
+bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
 {
     bool pkgIdIsNew = false;
     std::vector<std::string> addedPermissions;
@@ -165,6 +200,12 @@ bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &s
     Deserialization::Deserialize(buffer, req.privileges);
     Deserialization::Deserialize(buffer, req.appPaths);
 
+    if(!installRequestAuthCheck(req, uid)) {
+        LogError("Request from uid " << uid << " for app installation denied");
+        Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED);
+        return false;
+    }
+
     std::string smackLabel;
     if (!generateAppLabel(req.pkgId, smackLabel)) {
         LogError("Cannot generate Smack label for package: " << req.pkgId);
@@ -211,10 +252,10 @@ bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &s
         std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
 
         m_privilegeDb.BeginTransaction();
-        m_privilegeDb.GetPkgPrivileges(req.pkgId, oldPkgPrivileges);
-        m_privilegeDb.AddApplication(req.appId, req.pkgId, pkgIdIsNew);
-        m_privilegeDb.UpdateAppPrivileges(req.appId, req.privileges);
-        m_privilegeDb.GetPkgPrivileges(req.pkgId, newPkgPrivileges);
+        m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
+        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
         m_privilegeDb.CommitTransaction();
         LogDebug("Application installation commited to database");
@@ -270,7 +311,7 @@ error_label:
     return false;
 }
 
-bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send)
+bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
 {
     // deserialize request data
     std::string appId;
@@ -307,10 +348,10 @@ bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer
             LogDebug("Unnstall parameters: appId: " << appId << ", pkgId: " << pkgId
                     << ", generated smack label: " << smackLabel);
 
-            m_privilegeDb.GetPkgPrivileges(pkgId, oldPkgPrivileges);
-            m_privilegeDb.UpdateAppPrivileges(appId, std::vector<std::string>());
-            m_privilegeDb.RemoveApplication(appId, removePkg);
-            m_privilegeDb.GetPkgPrivileges(pkgId, newPkgPrivileges);
+            m_privilegeDb.GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
+            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
             m_privilegeDb.CommitTransaction();
             LogDebug("Application uninstallation commited to database");