Add possibility of installing apps for different users
[platform/core/security/security-manager.git] / src / server / service / installer.cpp
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");