New API: check permission of app with given app_id (implementation) 52/187452/11
authorPawel Kowalski <p.kowalski2@partner.samsung.com>
Thu, 23 Aug 2018 08:09:58 +0000 (10:09 +0200)
committerPawel Kowalski <p.kowalski2@partner.samsung.com>
Wed, 26 Sep 2018 15:23:32 +0000 (17:23 +0200)
The new API provides a possibility of checking the privacy status of
the app with its app_id (the Smack label of the app may be different
than the caller's Smack label).

Required privilege:
- http://tizen.org/privilege/permission.check

Change-Id: I5a3897de40d285fb6066da96b81186af7e4e70ea

src/capi/impl/privacy_privilege_manager.c
src/client/api/ApiInterface.h
src/client/api/askuser-notification-client.cpp
src/client/impl/ApiInterfaceImpl.cpp
src/client/impl/ApiInterfaceImpl.h
src/client/impl/TryCatch.h
src/client/include/askuser-notification-client.h
src/common/exception/AuthenticationFailedException.h [new file with mode: 0644]
src/common/policy/Policy.cpp

index a99ea09..363dede 100644 (file)
@@ -83,6 +83,8 @@ static ppm_error_e ask_user_to_ppm_error(int ask_error)
             return  PRIVACY_PRIVILEGE_MANAGER_ERROR_IO_ERROR;
         case ASKUSER_API_ALREADY_IN_PROGRESS:
             return  PRIVACY_PRIVILEGE_MANAGER_ERROR_ALREADY_IN_PROGRESS;
+        case ASKUSER_API_PERMISSION_DENIED:
+            return PRIVACY_PRIVILEGE_MANAGER_ERROR_PERMISSION_DENIED;
         default:
             break;
     }
@@ -334,6 +336,29 @@ int ppm_check_permission(const char *privilege, ppm_check_result_e *result)
 }
 
 EXPORT_API
+int ppm_check_app_permission(const char *app_id, const char *privilege, ppm_check_result_e *result)
+{
+    if (!privilege || !result || !app_id) {
+        return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
+    }
+
+    int ret = ppm_init_client();
+    if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
+        return ret;
+    }
+
+    askuser_check_result check_result = ASKUSER_CHECK_RESULT_DENY;
+    ret = askuser_client_check_app_privilege(ppm_handle->client, app_id, privilege, &check_result);
+    if (ret != ASKUSER_API_SUCCESS) {
+        return ask_user_to_ppm_error(ret);
+    }
+
+    *result = ask_user_check_result_to_ppm(check_result);
+
+    return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
+}
+
+EXPORT_API
 int ppm_check_permissions(const char **privileges, size_t privileges_count,
                           ppm_check_result_e *results)
 {
@@ -371,6 +396,43 @@ int ppm_check_permissions(const char **privileges, size_t privileges_count,
 }
 
 EXPORT_API
+int ppm_check_app_permissions(const char *app_id, const char **privileges,
+                              size_t privileges_count, ppm_check_result_e *results)
+{
+    if (!privileges_count || !privileges || !results) {
+        return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
+    }
+    for (size_t iterator = 0; iterator < privileges_count; iterator++) {
+        if (!privileges[iterator]) {
+            return PRIVACY_PRIVILEGE_MANAGER_ERROR_INVALID_PARAMETER;
+        }
+    }
+
+    int ret = ppm_init_client();
+    if (ret != PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE) {
+        return ret;
+    }
+
+    askuser_check_result *check_results = malloc(privileges_count * sizeof(askuser_check_result));
+    if (!check_results) {
+        return PRIVACY_PRIVILEGE_MANAGER_ERROR_OUT_OF_MEMORY;
+    }
+
+    ret = askuser_client_check_app_privileges(ppm_handle->client, app_id, privileges, privileges_count, check_results);
+    if (ret != ASKUSER_API_SUCCESS) {
+        free(check_results);
+        return ask_user_to_ppm_error(ret);
+    }
+
+    for (size_t iterator = 0; iterator < privileges_count; iterator++) {
+        results[iterator] = ask_user_check_result_to_ppm(check_results[iterator]);
+    }
+
+    free(check_results);
+    return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
+}
+
+EXPORT_API
 int ppm_request_permission(const char *privilege, ppm_request_response_cb callback, void *user_data)
 {
     if (!privilege || !callback) {
index 2f6fd80..25cd4f3 100644 (file)
@@ -40,6 +40,8 @@ public:
     virtual ~ApiInterface() {}
 
     virtual int process(int fd, int events) = 0;
+    virtual askuser_check_result checkPrivilege(const std::string &app_id,
+                                                const std::string &privilege) = 0;
     virtual askuser_check_result checkPrivilege(const std::string &privilege) = 0;
     virtual RequestId popupRequest(const std::string &privilege,
                                    const askuser_popup_response_callback callback,
index 5da69fa..6377128 100644 (file)
@@ -115,6 +115,26 @@ int askuser_client_check_privilege(askuser_client *p_client,
 }
 
 API
+int askuser_client_check_app_privilege(askuser_client *p_client,
+                                       const char *app_id,
+                                       const char *privilege,
+                                       askuser_check_result *p_result)
+{
+    if (!p_client || !privilege || !p_result) {
+        return ASKUSER_API_INVALID_PARAM;
+    }
+
+    if (std::strlen(privilege) == 0) {
+        return ASKUSER_API_INVALID_PARAM;
+    }
+
+    return AskUser::Client::tryCatch([&]() {
+        *p_result = p_client->impl->checkPrivilege(app_id, privilege);
+        return ASKUSER_API_SUCCESS;
+    });
+}
+
+API
 int askuser_client_check_privileges(askuser_client *p_client, const char **privileges,
                                     size_t privileges_count, askuser_check_result *p_results)
 {
@@ -133,6 +153,25 @@ int askuser_client_check_privileges(askuser_client *p_client, const char **privi
 }
 
 API
+int askuser_client_check_app_privileges(askuser_client *p_client, const char *app_id,
+                                        const char **privileges, size_t privileges_count,
+                                        askuser_check_result *p_results)
+{
+    if (!p_client || !privileges || !p_results ||
+        privileges_count == 0 || privileges_count > AskUser::Protocol::MAX_PRIVS_NUMBER) {
+        return ASKUSER_API_INVALID_PARAM;
+    }
+
+    int ret = ASKUSER_API_SUCCESS;
+    for (size_t i = 0; i < privileges_count; ++i) {
+        ret = askuser_client_check_app_privilege(p_client, app_id, privileges[i], &(p_results[i]));
+        if (ret != ASKUSER_API_SUCCESS)
+            break;
+    }
+    return ret;
+}
+
+API
 int askuser_client_popup_request(askuser_client *p_client, const char *privilege,
                                  askuser_popup_response_callback response_callback,
                                  void *p_user_data, int *p_request_id)
index 5b6ed44..cf7d75b 100644 (file)
@@ -100,11 +100,17 @@ int ApiInterfaceImpl::process(int fd, int events)
     return m_channel->process(fd, eventsToAskUserMask(events));
 }
 
-askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privilege)
+askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &appId, const std::string &privilege)
 {
-    std::string appId = getOwnAppId(m_pkgInfo);
     PrivilegePolicy privPolicy(appId, privilege);
-    auto policyLevel = privPolicy.calculatePolicy(m_appInfo);
+    Policy policyLevel;
+    if (appId == getOwnAppId(m_pkgInfo)) {
+        policyLevel = privPolicy.calculatePolicy(m_appInfo);
+    } else {
+        PkgMgrAppInfo appInfo;
+        appInfo.type(appId, geteuid());
+        policyLevel = privPolicy.calculatePolicy(appInfo);
+    }
 
     if (policyLevel == "Allow") {
         return ASKUSER_CHECK_RESULT_ALLOW;
@@ -123,6 +129,11 @@ askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privile
     return ASKUSER_CHECK_RESULT_DENY;
 }
 
+askuser_check_result ApiInterfaceImpl::checkPrivilege(const std::string &privilege)
+{
+    return ApiInterfaceImpl::checkPrivilege(getOwnAppId(m_pkgInfo), privilege);
+}
+
 RequestId ApiInterfaceImpl::popupRequest(const std::string &privilege,
                                          const askuser_popup_response_callback callback,
                                          void *userData)
index 1c829a4..d70d80c 100644 (file)
@@ -51,6 +51,8 @@ public:
     ApiInterface &operator=(const ApiInterfaceImpl& orig) = delete;
 
     virtual int process(int fd, int events);
+    virtual askuser_check_result checkPrivilege(const std::string &appId,
+                                                const std::string &privilege);
     virtual askuser_check_result checkPrivilege(const std::string &privilege);
     virtual RequestId popupRequest(const std::string &privilege,
                                    const askuser_popup_response_callback callback,
index 51b7448..26bc3f8 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <log/alog.h>
 #include <connection-exception.h>
+#include <exception/AuthenticationFailedException.h>
 
 #include <askuser-notification-client.h>
 
@@ -40,6 +41,9 @@ int tryCatch(const std::function<int(void)> &func) {
     } catch (const Protocol::ConnectionException &e) {
         ALOGE(e.what());
         return ASKUSER_API_CONNECTION_ERROR;
+    } catch (const AuthenticationFailedException &e) {
+        ALOGE(e.what());
+        return ASKUSER_API_PERMISSION_DENIED;
     } catch (const std::bad_alloc &e) {
         ALOGE(e.what());
         return ASKUSER_API_OUT_OF_MEMORY;
index 8175516..a9d6f1c 100644 (file)
@@ -47,6 +47,9 @@
 /*! \brief indicating that a request has already been sent */
 #define ASKUSER_API_ALREADY_IN_PROGRESS -5
 
+/*! \brief indicating that a permission check was denied */
+#define ASKUSER_API_PERMISSION_DENIED -6
+
 /** @} */
 
 /**
@@ -395,6 +398,37 @@ int askuser_client_check_privilege(askuser_client *p_client, const char *privile
 
 /**
  * \brief Description
+ * This function is called to check if an application with a given app_id has access
+ * to a particular privilege.
+ *
+ * \par Purpose:
+ * This API function should be called if a calling application wants to check
+ * if an application with a given app_id has access to a given privilege.
+ *
+ * \par Sync (or) Async:
+ * This is a synchronous API.
+ *
+ * \par Thread-safety:
+ * This function is NOT thread-safe.
+ *
+ * Required privilege: http://tizen.org/privilege/permission.check
+ *
+ * \param[in]   p_client    An instance of the askuser_client structure previously
+ *                          created by askuser_client_initialize().
+ * \param[in]   app_id      The app_id of the app that is to be checked.
+ * \param[in]   privilege   Privilege that is to be checked.
+ * \param[out]  p_result    The result of a privilege check.
+ *
+ * \return ASKUSER_API_SUCCESS on success
+ * \return a negative value in case of an error (see "Status return codes")
+ */
+int askuser_client_check_app_privilege(askuser_client *p_client,
+                                       const char *app_id,
+                                       const char *privilege,
+                                       askuser_check_result *p_result);
+
+/**
+ * \brief Description
  * This function is called to check if an application has access to given
  * privileges.
  *
@@ -423,6 +457,38 @@ int askuser_client_check_privileges(askuser_client *p_client, const char **privi
 
 /**
  * \brief Description
+ * This function is called to check if an application with a given app_id has access
+ * to given privileges.
+ *
+ * \par Purpose:
+ * This API function should be called if a calling application wants to check
+ * if an application with a given app_id has access to given privileges.
+ *
+ * \par Sync (or) Async:
+ * This is a synchronous API.
+ *
+ * \par Thread-safety:
+ * This function is NOT thread-safe.
+ *
+ * Required privilege: http://tizen.org/privilege/permission.check
+ *
+ * \param[in]   p_client          An instance of the askuser_client structure previously
+ * \param[in]   app_id            The app_id of the app that is to be checked.
+ *                                created by askuser_client_initialize().
+ * \param[in]   privileges        Privileges array that is to be checked.
+ * \param[in]   privileges_count  The number of elements of the privileges and results arrays.
+ *                                The parameter value should not exceed 100.
+ * \param[out]  p_results         The results array of a privileges check.
+ *
+ * \return ASKUSER_API_SUCCESS on success
+ * \return a negative value in case of an error (see "Status return codes")
+ */
+int askuser_client_check_app_privileges(askuser_client *p_client, const char *app_id,
+                                        const char **privileges, size_t privileges_count,
+                                        askuser_check_result *p_results);
+
+/**
+ * \brief Description
  * This function is called to determine a privacy privilege .
  *
  * \par Purpose:
diff --git a/src/common/exception/AuthenticationFailedException.h b/src/common/exception/AuthenticationFailedException.h
new file mode 100644 (file)
index 0000000..0e6ae89
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2018 Samsung Electronics Co.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/**
+ * @file        src/common/AuthenticationFailedException.h
+ * @author      Pawel Kowalski <p.kowalski@partner.samsung.com>
+ * @brief       Declaration of AuthenticationFailedException
+ */
+
+#pragma once
+
+#include <exception>
+#include <string>
+
+#include "Exception.h"
+
+namespace AskUser {
+
+class AuthenticationFailedException : public Exception
+{
+public:
+    AuthenticationFailedException(const std::string &function) {
+        m_msg = "Authentication failed in following function: " + function;
+    }
+};
+
+} /* namespace AskUser */
index 22ef685..94f3bf9 100644 (file)
@@ -27,6 +27,7 @@
 #include <security-manager.h>
 
 #include <exception/Exception.h>
+#include <exception/AuthenticationFailedException.h>
 #include <log/alog.h>
 
 #include "Policy.h"
@@ -79,6 +80,9 @@ std::set<Privilege> getManifestPrivs(const std::string &appId)
     int ret = security_manager_get_app_manifest_policy(appId.c_str(), geteuid(),
                                                        &privsRaw, &privsCount);
     if (ret != SECURITY_MANAGER_SUCCESS) {
+        if (ret == SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED) {
+            throw AuthenticationFailedException("security_manager_get_app_manifest_policy");
+        }
         ALOGE("Failed to fetch manifest privileges for app " << appId << " : " << ret);
         return {};
     }