From: Pawel Kowalski
Date: Thu, 23 Aug 2018 08:09:58 +0000 (+0200)
Subject: New API: check permission of app with given app_id (implementation)
X-Git-Tag: submit/tizen/20180927.110544~2
X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b451016d540b781b035ea3bb19c6df91b65e9bcf;p=platform%2Fcore%2Fsecurity%2Faskuser.git
New API: check permission of app with given app_id (implementation)
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
---
diff --git a/src/capi/impl/privacy_privilege_manager.c b/src/capi/impl/privacy_privilege_manager.c
index a99ea09..363dede 100644
--- a/src/capi/impl/privacy_privilege_manager.c
+++ b/src/capi/impl/privacy_privilege_manager.c
@@ -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;
}
@@ -333,6 +335,29 @@ int ppm_check_permission(const char *privilege, ppm_check_result_e *result)
return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
}
+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)
@@ -370,6 +395,43 @@ int ppm_check_permissions(const char **privileges, size_t privileges_count,
return PRIVACY_PRIVILEGE_MANAGER_ERROR_NONE;
}
+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)
{
diff --git a/src/client/api/ApiInterface.h b/src/client/api/ApiInterface.h
index 2f6fd80..25cd4f3 100644
--- a/src/client/api/ApiInterface.h
+++ b/src/client/api/ApiInterface.h
@@ -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,
diff --git a/src/client/api/askuser-notification-client.cpp b/src/client/api/askuser-notification-client.cpp
index 5da69fa..6377128 100644
--- a/src/client/api/askuser-notification-client.cpp
+++ b/src/client/api/askuser-notification-client.cpp
@@ -114,6 +114,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)
@@ -132,6 +152,25 @@ int askuser_client_check_privileges(askuser_client *p_client, const char **privi
return ret;
}
+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,
diff --git a/src/client/impl/ApiInterfaceImpl.cpp b/src/client/impl/ApiInterfaceImpl.cpp
index 5b6ed44..cf7d75b 100644
--- a/src/client/impl/ApiInterfaceImpl.cpp
+++ b/src/client/impl/ApiInterfaceImpl.cpp
@@ -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)
diff --git a/src/client/impl/ApiInterfaceImpl.h b/src/client/impl/ApiInterfaceImpl.h
index 1c829a4..d70d80c 100644
--- a/src/client/impl/ApiInterfaceImpl.h
+++ b/src/client/impl/ApiInterfaceImpl.h
@@ -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,
diff --git a/src/client/impl/TryCatch.h b/src/client/impl/TryCatch.h
index 51b7448..26bc3f8 100644
--- a/src/client/impl/TryCatch.h
+++ b/src/client/impl/TryCatch.h
@@ -27,6 +27,7 @@
#include
#include
+#include
#include
@@ -40,6 +41,9 @@ int tryCatch(const std::function &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;
diff --git a/src/client/include/askuser-notification-client.h b/src/client/include/askuser-notification-client.h
index 8175516..a9d6f1c 100644
--- a/src/client/include/askuser-notification-client.h
+++ b/src/client/include/askuser-notification-client.h
@@ -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
+
/** @} */
/**
@@ -393,6 +396,37 @@ int askuser_client_process(askuser_client *p_client, int fd, int events);
int askuser_client_check_privilege(askuser_client *p_client, const char *privilege,
askuser_check_result *p_result);
+/**
+ * \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
@@ -421,6 +455,38 @@ int askuser_client_check_privilege(askuser_client *p_client, const char *privile
int askuser_client_check_privileges(askuser_client *p_client, const char **privileges,
size_t privileges_count, askuser_check_result *p_results);
+/**
+ * \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 .
diff --git a/src/common/exception/AuthenticationFailedException.h b/src/common/exception/AuthenticationFailedException.h
new file mode 100644
index 0000000..0e6ae89
--- /dev/null
+++ b/src/common/exception/AuthenticationFailedException.h
@@ -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
+ * @brief Declaration of AuthenticationFailedException
+ */
+
+#pragma once
+
+#include
+#include
+
+#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 */
diff --git a/src/common/policy/Policy.cpp b/src/common/policy/Policy.cpp
index 22ef685..94f3bf9 100644
--- a/src/common/policy/Policy.cpp
+++ b/src/common/policy/Policy.cpp
@@ -27,6 +27,7 @@
#include
#include
+#include
#include
#include "Policy.h"
@@ -79,6 +80,9 @@ std::set 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 {};
}