Don't check permissions on API calls in off-line mode 17/68017/1
authorRafal Krypa <r.krypa@samsung.com>
Fri, 29 Apr 2016 17:44:12 +0000 (19:44 +0200)
committerRafal Krypa <r.krypa@samsung.com>
Fri, 29 Apr 2016 17:46:17 +0000 (19:46 +0200)
Off-line mode was introduced to be used during image creation, when no
services are running. It enables root to perform some security-manager
operations on the client side.

But in off-line mode not only security-manager isn't running. No services
run, including cynara service. When libsecurity-manager-client tries to
check whether the off-line mode user has access to proper privilege, it
fails because cynara_check() has no off-line mode.

Permission checking in such scenario isn't required. The user is already
checked for UID 0 and even if it gets away from that check, it wouldn't be
able to perform actual operations without being super user.

Change-Id: I087bbc6b29a702a445d4498b96a950ca1e919efd
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
src/client/client-offline.cpp
src/client/client-security-manager.cpp
src/client/include/client-offline.h
src/common/include/credentials.h
src/common/include/service_impl.h
src/common/service_impl.cpp

index 159d28b..c2d95df 100644 (file)
@@ -81,4 +81,12 @@ bool ClientOffline::isOffline(void)
     return offlineMode;
 }
 
+Credentials ClientOffline::getCredentials()
+{
+    Credentials creds = Credentials::getCredentialsFromSelf();
+    if (isOffline())
+        creds.authenticated = true;
+    return creds;
+}
+
 } // namespace SecurityManager
index 6b35e74..28403c6 100755 (executable)
@@ -47,7 +47,6 @@
 #include <protocols.h>
 #include <service_impl.h>
 #include <connection.h>
-#include <credentials.h>
 
 #include <security-manager.h>
 #include <client-offline.h>
@@ -204,7 +203,7 @@ int security_manager_app_install(const app_inst_req *p_req)
         int retval;
         ClientOffline offlineMode;
         if (offlineMode.isOffline()) {
-            Credentials creds = SecurityManager::Credentials::getCredentialsFromSelf();
+            Credentials creds = offlineMode.getCredentials();
             retval = SecurityManager::ServiceImpl().appInstall(creds, app_inst_req(*p_req));
         } else {
             MessageBuffer send, recv;
@@ -592,7 +591,7 @@ int security_manager_user_add(const user_req *p_req)
         int retval;
         ClientOffline offlineMode;
         if (offlineMode.isOffline()) {
-            Credentials creds = SecurityManager::Credentials::getCredentialsFromSelf();
+            Credentials creds = offlineMode.getCredentials();
             retval = SecurityManager::ServiceImpl().userAdd(creds, p_req->uid, p_req->utype);
         } else {
             MessageBuffer send, recv;
index 3f2e421..d50fc6f 100644 (file)
@@ -25,6 +25,7 @@
 #ifndef _SECURITY_MANAGER_OFFLINE_
 #define _SECURITY_MANAGER_OFFLINE_
 
+#include <credentials.h>
 #include <file-lock.h>
 
 namespace SecurityManager {
@@ -34,6 +35,7 @@ public:
     ClientOffline();
     ~ClientOffline();
     bool isOffline(void);
+    Credentials getCredentials();
 
 private:
     bool offlineMode;
index 003a37e..06546fc 100644 (file)
@@ -35,6 +35,7 @@ public:
     uid_t uid;    /* user ID of the sending process */
     gid_t gid;    /* group ID of the sending process */
     std::string label; /* security context of the sending process */
+    bool authenticated = false;   /* Indicate that the caller has already been authenticated for access */
 
     Credentials() = delete;
     static Credentials getCredentialsFromSelf(void);
index bae4c79..313ae0e 100644 (file)
@@ -36,6 +36,8 @@ namespace SecurityManager {
 
 class ServiceImpl {
 private:
+    static bool authenticate(const Credentials &creds, const std::string &privilege);
+
     static uid_t getGlobalUserId(void);
 
     static bool isSubDir(const char *parent, const char *subdir);
@@ -75,11 +77,10 @@ public:
     *
     * @param[in] creds credentials of the requesting process
     * @param[in] req uninstallation request
-    * @param[in] authenticated whether the caller has been already checked against Cynara policy
     *
     * @return API return code, as defined in protocols.h
     */
-    int appUninstall(const Credentials &creds, app_inst_req &&req, bool authenticated = false);
+    int appUninstall(const Credentials &creds, app_inst_req &&req);
 
     /**
     * Process package id query.
index bd8e740..60c0317 100755 (executable)
@@ -174,6 +174,14 @@ ServiceImpl::~ServiceImpl()
 {
 }
 
+bool ServiceImpl::authenticate(const Credentials &creds, const std::string &privilege)
+{
+    if (creds.authenticated)
+        return true;
+    return Cynara::getInstance().check(creds.label, privilege,
+        std::to_string(creds.uid), std::to_string(creds.pid));
+}
+
 uid_t ServiceImpl::getGlobalUserId(void)
 {
     static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
@@ -266,16 +274,14 @@ void ServiceImpl::installRequestMangle(app_inst_req &req, std::string &cynaraUse
 
 bool ServiceImpl::installRequestAuthCheck(const Credentials &creds, const app_inst_req &req)
 {
-    if (req.installationType != SM_APP_INSTALL_LOCAL || req.uid != creds.uid) {
-        if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_APPINST_ADMIN,
-            std::to_string(creds.uid), std::to_string(creds.pid))) {
-            LogError("Caller is not permitted to install applications globally");
+    if (req.installationType == SM_APP_INSTALL_LOCAL && req.uid == creds.uid) {
+        if (!authenticate(creds, Config::PRIVILEGE_APPINST_USER)) {
+            LogError("Caller is not permitted to install applications locally");
             return false;
         }
     } else {
-        if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_APPINST_USER,
-            std::to_string(creds.uid), std::to_string(creds.pid))) {
-            LogError("Caller is not permitted to install applications");
+        if (!authenticate(creds, Config::PRIVILEGE_APPINST_ADMIN)) {
+            LogError("Caller is not permitted to install applications globally");
             return false;
         }
     }
@@ -429,8 +435,7 @@ int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &&req)
     return SECURITY_MANAGER_SUCCESS;
 }
 
-int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &&req,
-    bool authenticated)
+int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &&req)
 {
     std::string tizenVersion;
     std::string smackLabel;
@@ -446,7 +451,7 @@ int ServiceImpl::appUninstall(const Credentials &creds, app_inst_req &&req,
 
     LogDebug("Uninstall parameters: appName=" << req.appName << ", uid=" << req.uid);
 
-    if (!authenticated && !installRequestAuthCheck(creds, req)) {
+    if (!installRequestAuthCheck(creds, req)) {
         LogError("Request from uid=" << creds.uid << ", Smack=" << creds.label <<
             " for app uninstallation denied");
         return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
@@ -625,9 +630,7 @@ int ServiceImpl::getAppGroups(const Credentials &creds, const std::string &appNa
 
 int ServiceImpl::userAdd(const Credentials &creds, uid_t uidAdded, int userType)
 {
-    if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_USER_ADMIN,
-        std::to_string(creds.uid), std::to_string(creds.pid))) {
-
+    if (!authenticate(creds, Config::PRIVILEGE_USER_ADMIN)) {
         LogError("Caller is not permitted to manage users");
         return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
     }
@@ -644,9 +647,7 @@ int ServiceImpl::userDelete(const Credentials &creds, uid_t uidDeleted)
 {
     int ret = SECURITY_MANAGER_SUCCESS;
 
-    if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_USER_ADMIN,
-        std::to_string(creds.uid), std::to_string(creds.pid))) {
-
+    if (!authenticate(creds, Config::PRIVILEGE_USER_ADMIN)) {
         LogError("Caller is not permitted to manage users");
         return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
     }
@@ -660,11 +661,14 @@ int ServiceImpl::userDelete(const Credentials &creds, uid_t uidDeleted)
         return SECURITY_MANAGER_ERROR_SERVER_ERROR;
     }
 
+    // Don't check whether the caller may uninstall apps of the removed user
+    Credentials credsTmp(creds);
+    credsTmp.authenticated = true;
     for (const auto &app : userApps) {
         app_inst_req req;
         req.uid = uidDeleted;
         req.appName = app;
-        if (appUninstall(creds, std::move(req), true) != SECURITY_MANAGER_SUCCESS) {
+        if (appUninstall(credsTmp, std::move(req)) != SECURITY_MANAGER_SUCCESS) {
         /*if uninstallation of this app fails, just go on trying to uninstall another ones.
         we do not have anything special to do about that matter - user will be deleted anyway.*/
             ret = SECURITY_MANAGER_ERROR_SERVER_ERROR;
@@ -709,14 +713,12 @@ int ServiceImpl::policyUpdate(const Credentials &creds, const std::vector<policy
         };
 
         // Check privileges
-        if (permUserRequired && !Cynara::getInstance().check(creds.label,
-                Config::PRIVILEGE_POLICY_USER, uidStr, pidStr)) {
+        if (permUserRequired && !authenticate(creds, Config::PRIVILEGE_POLICY_USER)) {
             LogError("Not enough privilege to enforce user policy");
             return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
         }
 
-        if (permAdminRequired && !Cynara::getInstance().check(creds.label,
-                Config::PRIVILEGE_POLICY_ADMIN, uidStr, pidStr)) {
+        if (permAdminRequired && !authenticate(creds, Config::PRIVILEGE_POLICY_ADMIN)) {
             LogError("Not enough privilege to enforce admin policy");
             return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
         }
@@ -759,7 +761,7 @@ int ServiceImpl::getConfiguredPolicy(const Credentials &creds, bool forAdmin,
         LogDebug("App: " << filter.appName << ", Label: " << appLabel);
 
         if (forAdmin) {
-            if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_POLICY_ADMIN, uidStr, pidStr)) {
+            if (!authenticate(creds, Config::PRIVILEGE_POLICY_ADMIN)) {
                 LogError("Not enough privilege to access admin enforced policies");
                 return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
             }
@@ -774,13 +776,13 @@ int ServiceImpl::getConfiguredPolicy(const Credentials &creds, bool forAdmin,
                 );
             LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
         } else {
-            if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_POLICY_USER, uidStr, pidStr)) {
+            if (!authenticate(creds, Config::PRIVILEGE_POLICY_USER)) {
                 LogError("Not enough privilege to access user enforced policies");
                 return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
             }
 
             if (uidStr.compare(user)) {
-                if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_POLICY_ADMIN, uidStr, pidStr)) {
+                if (!authenticate(creds, Config::PRIVILEGE_POLICY_ADMIN)) {
                     LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
                     user = uidStr;
                 };
@@ -852,7 +854,7 @@ int ServiceImpl::getPolicy(const Credentials &creds, const policy_entry &filter,
         std::string uidStr = std::to_string(creds.uid);
         std::string pidStr = std::to_string(creds.pid);
 
-        if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_POLICY_USER, uidStr, pidStr)) {
+        if (!authenticate(creds, Config::PRIVILEGE_POLICY_USER)) {
             LogWarning("Not enough permission to call: " << __FUNCTION__);
             return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
         };
@@ -866,7 +868,7 @@ int ServiceImpl::getPolicy(const Credentials &creds, const policy_entry &filter,
 
         std::vector<uid_t> listOfUsers;
 
-        if (Cynara::getInstance().check(creds.label, Config::PRIVILEGE_POLICY_ADMIN, uidStr, pidStr)) {
+        if (authenticate(creds, Config::PRIVILEGE_POLICY_ADMIN)) {
             LogDebug("User is privileged");
             if (filter.user.compare(SECURITY_MANAGER_ANY)) {
                 LogDebug("Limitting Cynara query to user: " << filter.user);
@@ -1088,8 +1090,7 @@ int ServiceImpl::applyPrivatePathSharing(
     std::vector<std::string> pkgContents;
 
     try {
-        if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_APPSHARING_ADMIN,
-            std::to_string(creds.uid), std::to_string(creds.pid))) {
+        if (!authenticate(creds, Config::PRIVILEGE_APPSHARING_ADMIN)) {
             LogError("Caller is not permitted to manage file sharing");
             return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
         }
@@ -1182,8 +1183,7 @@ int ServiceImpl::dropPrivatePathSharing(
 {
     int errorRet;
     try {
-        if (!Cynara::getInstance().check(creds.label, Config::PRIVILEGE_APPSHARING_ADMIN,
-            std::to_string(creds.uid), std::to_string(creds.pid))) {
+        if (!authenticate(creds, Config::PRIVILEGE_APPSHARING_ADMIN)) {
             LogError("Caller is not permitted to manage file sharing");
             return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
         }