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 {}; }