From 536102ce612c9d61053e1dca4e87f04d30e00c28 Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Fri, 18 Jul 2014 17:35:41 +0200 Subject: [PATCH] Add possibility of installing apps for different users 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 --- src/server/db/db.sql | 11 +++--- src/server/db/include/privilege_db.h | 25 +++++++------ src/server/db/privilege_db.cpp | 19 ++++++---- src/server/service/include/installer.h | 8 +++-- src/server/service/installer.cpp | 65 +++++++++++++++++++++++++++------- 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/src/server/db/db.sql b/src/server/db/db.sql index 680c2ed..513a664 100644 --- a/src/server/db/db.sql +++ b/src/server/db/db.sql @@ -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; diff --git a/src/server/db/include/privilege_db.h b/src/server/db/include/privilege_db.h index b90c1c0..7890022 100644 --- a/src/server/db/include/privilege_db.h +++ b/src/server/db/include/privilege_db.h @@ -61,11 +61,11 @@ class PrivilegeDb { private: SecurityManager::DB::SqlConnection *mSqlConnection; const std::map 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 ¤tPrivilege); /** @@ -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 &privileges); }; diff --git a/src/server/db/privilege_db.cpp b/src/server/db/privilege_db.cpp index 5eafde6..32e18b4 100644 --- a/src/server/db/privilege_db.cpp +++ b/src/server/db/privilege_db.cpp @@ -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(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([&] { @@ -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(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 ¤tPrivileges) { try_catch([&] { @@ -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(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([&] { DB::SqlConnection::DataCommandAutoPtr command = mSqlConnection->PrepareDataCommand(Queries.at(QueryType::ERemoveAppPrivileges)); command->BindString(1, appId.c_str()); + command->BindInteger(2, static_cast(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 &privileges) { try_catch([&] { DB::SqlConnection::DataCommandAutoPtr command = mSqlConnection->PrepareDataCommand(Queries.at(QueryType::EAddAppPrivileges)); command->BindString(1, appId.c_str()); + command->BindInteger(2, static_cast(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); diff --git a/src/server/service/include/installer.h b/src/server/service/include/installer.h index c1f8d42..1a7caf2 100644 --- a/src/server/service/include/installer.h +++ b/src/server/service/include/installer.h @@ -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 diff --git a/src/server/service/installer.cpp b/src/server/service/installer.cpp index 8f7bb0c..6451dc8 100644 --- a/src/server/service/installer.cpp +++ b/src/server/service/installer.cpp @@ -27,6 +27,8 @@ #include #include +#include +#include #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(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 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 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()); - m_privilegeDb.RemoveApplication(appId, removePkg); - m_privilegeDb.GetPkgPrivileges(pkgId, newPkgPrivileges); + m_privilegeDb.GetPkgPrivileges(pkgId, uid, oldPkgPrivileges); + m_privilegeDb.UpdateAppPrivileges(appId, uid, std::vector()); + 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"); -- 2.7.4