From: Dongsun Lee Date: Thu, 9 Jan 2025 07:09:06 +0000 (+0900) Subject: Replace access control mechansm from white list to privilege. X-Git-Tag: accepted/tizen/unified/20250225.162935~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b13a0ae981d8fc8050e1817d0e709cda50f5b31c;p=platform%2Fcore%2Fsecurity%2Fauth-fw.git Replace access control mechansm from white list to privilege. - The current white list implementation needs to access /proc/xxx/attr/current. - We have to remove the codes directly accessing above file. - And the auth-fw is not a proper place to manage the while list because each division may want to change it on its own. - The privilege is more flexible than white list. required privilege: "http://tizen.org/privilege/internal/default/platform" Change-Id: I036ecd132fb163adc58b2e721b448c7a2668e33c --- diff --git a/CMakeLists.txt b/CMakeLists.txt index ef41879..c7f5427 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,5 +86,4 @@ SET(TARGET_TEST ${SERVICE_NAME}-test) ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(pkgconfig) ADD_SUBDIRECTORY(systemd) -ADD_SUBDIRECTORY(conf) ADD_SUBDIRECTORY(tests) diff --git a/conf/CMakeLists.txt b/conf/CMakeLists.txt deleted file mode 100644 index 7178786..0000000 --- a/conf/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved -# -# 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 CMakeLists.txt -# @author Jooseong Lee -# - -INSTALL(FILES client-whitelist DESTINATION ${SYS_CONFIG_DIR}/${SERVICE_NAME}) -INSTALL(FILES admin-client-whitelist DESTINATION ${SYS_CONFIG_DIR}/${SERVICE_NAME}) diff --git a/conf/admin-client-whitelist b/conf/admin-client-whitelist deleted file mode 100644 index 5e88c28..0000000 --- a/conf/admin-client-whitelist +++ /dev/null @@ -1,4 +0,0 @@ -# subject labels allowed to use password reset and password policy setting -# put each allowed label in new line -System -System::Privileged diff --git a/conf/client-whitelist b/conf/client-whitelist deleted file mode 100644 index a066890..0000000 --- a/conf/client-whitelist +++ /dev/null @@ -1,11 +0,0 @@ -# subject labels allowed to use password checking/setting -# put each allowed label in new line -# If the preloaded app can hold internal privilege later, -# the whitelist would be replaced with cynara. -System -System::Privileged -User -# This is for the mobile preloaded app. -User::Pkg::org.tizen.keyguard -User::Pkg::org.tizen.lockscreen -User::Pkg::org.tizen.setting diff --git a/packaging/auth-fw-test.manifest b/packaging/auth-fw-test.manifest index 94a93ea..a76fdba 100644 --- a/packaging/auth-fw-test.manifest +++ b/packaging/auth-fw-test.manifest @@ -2,7 +2,4 @@ - - - diff --git a/packaging/auth-fw.spec b/packaging/auth-fw.spec index 1d733a2..aeb985b 100644 --- a/packaging/auth-fw.spec +++ b/packaging/auth-fw.spec @@ -15,6 +15,9 @@ BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(libsystemd) BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-creds-socket) +BuildRequires: pkgconfig(cynara-session) Requires: security-config Requires: lib%{name}-sw-backend = %{version}-%{release} %{?systemd_requires} @@ -83,7 +86,6 @@ export CXXFLAGS+=" -Wno-maybe-uninitialized" -DCMAKE_VERBOSE_MAKEFILE=ON \ -DSERVICE_NAME=%{name} \ -DBIN_DIR:PATH=%{bin_dir} \ - -DSYS_CONFIG_DIR:PATH=%{_sysconfdir} \ -DRUN_DIR:PATH=%{run_dir} \ -DRW_DATA_DIR:PATH=%{rw_data_dir} \ -DPLUGIN_DIR:PATH=%{plugin_dir} \ @@ -161,8 +163,6 @@ fi %{_unitdir}/sockets.target.wants/%{sock_passwd_set} %{_unitdir}/sockets.target.wants/%{sock_passwd_reset} %{_unitdir}/sockets.target.wants/%{sock_passwd_policy} -%{_sysconfdir}/%{name}/client-whitelist -%{_sysconfdir}/%{name}/admin-client-whitelist %dir %attr(770, %{user_name}, %{group_name}) %{rw_data_dir} %files -n lib%{name}-client @@ -208,6 +208,7 @@ SW-Backend for authentication framework Summary: Authentication framework (test) Group: Security/Testing BuildRequires: pkgconfig(klay) +BuildRequires: pkgconfig(security-manager) Requires: %{name} = %{version} %description test diff --git a/src/include/auth-passwd-admin.h b/src/include/auth-passwd-admin.h index c260373..8f14a60 100644 --- a/src/include/auth-passwd-admin.h +++ b/src/include/auth-passwd-admin.h @@ -68,6 +68,11 @@ extern "C" { * no checks before password replacement (expiration time check, currently set password checks, * history check and attempt count check are skipped). * + * \par Client privilege: + * This API requires the following privilege. It means only an internal module or + * an application with the platform privilege can call this API. + * - http://tizen.org/privilege/internal/default/platform + * * \par Sync (or) Async: * This is a Synchronous API. * @@ -270,6 +275,11 @@ int auth_passwd_set_forbidden_passwd(policy_h *p_policy, const char *forbidden_p * if policies is valid. When there are new polices for max attempts and valid period, * these policies apply to current normal(lock) password immediately. * + * \par Client privilege: + * This API requires the following privilege. It means only an internal module or + * an application with the platform privilege can call this API. + * - http://tizen.org/privilege/internal/default/platform + * * \par Sync (or) Async: * This is a Synchronous API. * diff --git a/src/include/auth-passwd.h b/src/include/auth-passwd.h index 2fa6556..6e5f913 100644 --- a/src/include/auth-passwd.h +++ b/src/include/auth-passwd.h @@ -65,6 +65,11 @@ extern "C" { * \par Method of function operation: * Sends input password to auth-fw, auth-fw compares hashed current password and hashed input password. * + * \par Client privilege: + * This API requires the following privilege. It means only an internal module or + * an application with the platform privilege can call this API. + * - http://tizen.org/privilege/internal/default/platform + * * \par Sync (or) Async: * This is a Synchronous API. * @@ -149,6 +154,11 @@ int auth_passwd_check_passwd(password_type passwd_type, * \par Method of function operation: * Sends a validate request to auth-fw and auth-fw replies with password information. * + * \par Client privilege: + * This API requires the following privilege. It means only an internal module or + * an application with the platform privilege can call this API. + * - http://tizen.org/privilege/internal/default/platform + * * \par Sync (or) Async: * This is a Synchronous API. * @@ -221,6 +231,11 @@ int auth_passwd_check_passwd_state(password_type passwd_type, * \par Method of function operation: * Sends a check request to auth-fw and auth-fw replies with password availability. * + * \par Client privilege: + * This API requires the following privilege. It means only an internal module or + * an application with the platform privilege can call this API. + * - http://tizen.org/privilege/internal/default/platform + * * \par Sync (or) Async: * This is a Synchronous API. * @@ -272,6 +287,11 @@ int auth_passwd_check_passwd_available(password_type passwd_type, const char *pa * \par Method of function operation: * Sends a check request to auth-fw and auth-fw replies with password reusability information. * + * \par Client privilege: + * This API requires the following privilege. It means only an internal module or + * an application with the platform privilege can call this API. + * - http://tizen.org/privilege/internal/default/platform + * * \par Sync (or) Async: * This is a Synchronous API. * @@ -314,6 +334,11 @@ int auth_passwd_check_passwd_reused(password_type passwd_type, * checks current password and set new password to current only when current * password is correct and new password meet password policies. * + * \par Client privilege: + * This API requires the following privilege. It means only an internal module or + * an application with the platform privilege can call this API. + * - http://tizen.org/privilege/internal/default/platform + * * \par Sync (or) Async: * This is a Synchronous API. * diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index cecadd3..279d3f0 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -2,6 +2,9 @@ PKG_CHECK_MODULES(SERVER_DEP REQUIRED libsmack libsystemd + cynara-client + cynara-creds-socket + cynara-session ) FIND_PACKAGE(Threads REQUIRED) @@ -20,6 +23,7 @@ INCLUDE_DIRECTORIES( SET(SERVER_SOURCES main/generic-socket-manager.cpp + main/privilege-check.cpp main/server-main.cpp main/smack-check.cpp main/socket-manager.cpp diff --git a/src/server/main/include/privilege-check.h b/src/server/main/include/privilege-check.h new file mode 100644 index 0000000..532d314 --- /dev/null +++ b/src/server/main/include/privilege-check.h @@ -0,0 +1,65 @@ +/* + * Authentication password + * + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jooseong Lee + * + * 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 + */ + +#ifndef _PRIVILEGE_CHECK_H_ +#define _PRIVILEGE_CHECK_H_ + +#include +#include + +#include + +namespace AuthPasswd { + +const std::string PLATFORM_PRIVILEGE = "http://tizen.org/privilege/internal/default/platform"; + +class CynaraChecker { +public: + // singleton pattern + static CynaraChecker& instance() { + static CynaraChecker inst; // created once + return inst; + } + + // deletes copy constructor & copy assignment operator + CynaraChecker(const CynaraChecker&) = delete; + CynaraChecker& operator=(const CynaraChecker&) = delete; + + // deletes move constructor & move assignment operator + CynaraChecker(CynaraChecker&&) = delete; + CynaraChecker& operator=(CynaraChecker&) = delete; + + // calls cynara_finish(); + ~CynaraChecker(); + + // checks if a client has the given privilege. + bool checkClientPrivilege(int sockfd, const std::string& privilege); + +private: + cynara* m_CynaraInstance; + + // calls cynara_initialize() + CynaraChecker(); +}; + + +} // namespace AuthPasswd + +#endif // _PRIVILEGE_CHECK_H_ diff --git a/src/server/main/include/smack-check.h b/src/server/main/include/smack-check.h index 024c670..76b46b3 100644 --- a/src/server/main/include/smack-check.h +++ b/src/server/main/include/smack-check.h @@ -35,12 +35,6 @@ extern const std::string ADMIN_CLIENT_WHITELIST; */ int smack_check(void); -/* - * Check whether client is allowed or not on whitelist. - * Returns true if client label is present, fail otherwise. - */ -bool checkClientOnWhitelist(int sockfd, std::string whitelistPath); - } // namespace AuthPasswd #endif // _SMACK_CHECK_H_ diff --git a/src/server/main/privilege-check.cpp b/src/server/main/privilege-check.cpp new file mode 100644 index 0000000..562f93d --- /dev/null +++ b/src/server/main/privilege-check.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 + */ +/* + * @author Dongsun Lee(ds73.lee@samsung.com) + * @version 1.0 + * @brief Check client's privilege + */ +#include "privilege-check.h" + +#include + +#include +#include + + +namespace AuthPasswd { + +struct string_free_deleter { + void operator()(char * p) const { + free(p); + } +}; + +static inline std::string cynara_error_to_string(int error) { + char buffer[256]; + int ret = cynara_strerror(error, buffer, sizeof(buffer)); + if(ret == CYNARA_API_SUCCESS) + return std::string(buffer); + return std::string("Can't translate error"); +} + +CynaraChecker::CynaraChecker() +{ + cynara_configuration* cynara_conf = nullptr; + int error = cynara_configuration_create(&cynara_conf); + if(error != CYNARA_API_SUCCESS) { + LogError("Can't initialize Cynara configuration: " << error); + throw std::runtime_error("Can't initialize Cynara configuration"); + } + + error = cynara_initialize(&m_CynaraInstance, cynara_conf); + cynara_configuration_destroy(cynara_conf); + if(error != CYNARA_API_SUCCESS) { + LogError("Can't initialize Cynara instance: " << error); + throw std::runtime_error("Can't initialize Cynara instance"); + } + + LogDebug("CynaraChecker: cynara_initialize() was done."); +} + +CynaraChecker::~CynaraChecker() +{ + cynara_finish(m_CynaraInstance); + LogDebug("CynaraChecker: cynara_finish() was done."); +} + + +bool CynaraChecker::checkClientPrivilege(int sockfd, const std::string& privilege) +{ + int ret = 0; + char* tmp_str; + pid_t pid = 0; + + std::unique_ptr user; + std::unique_ptr client; + std::unique_ptr client_session; + + /* Get user info */ + tmp_str = nullptr; + ret = cynara_creds_socket_get_user(sockfd, USER_METHOD_DEFAULT, &tmp_str); + if(ret != CYNARA_API_SUCCESS) { + LogError("Can't get user from socket : " << ret << " - " << cynara_error_to_string(ret)); + return false; + } + user.reset(tmp_str); + + /* Get client info */ + tmp_str = nullptr; + ret = cynara_creds_socket_get_client(sockfd, CLIENT_METHOD_DEFAULT, &tmp_str); + if(ret != CYNARA_API_SUCCESS) { + LogError("Can't get client from socket : " << ret << " - " << cynara_error_to_string(ret)); + return false; + } + client.reset(tmp_str); + + /* Get client PID from socket */ + ret = cynara_creds_socket_get_pid(sockfd, &pid); + if(ret != CYNARA_API_SUCCESS) { + LogError("Can't get PID from socket : " << ret << " - " << cynara_error_to_string(ret)); + return false; + } + + client_session.reset(cynara_session_from_pid(pid)); + if(!client_session) { + LogError("Can't get session identifier from PID"); + return false; + } + + LogDebug("Got new session from " << pid << " with user " << user.get() << + ", client ID " << client.get() << " and session ID " << client_session.get()); + + ret = cynara_check(m_CynaraInstance, client.get(), client_session.get(), user.get(), privilege.c_str()); + + if(ret != CYNARA_API_ACCESS_ALLOWED) { + LogError("Application access denied for " << pid << ", privilege: " << + privilege << ", error: - " << cynara_error_to_string(ret)); + return false; + } + + LogDebug("Access granted for " << pid << " with privilege " << privilege); + return true; +} + +} // namespace AuthPasswd diff --git a/src/server/main/smack-check.cpp b/src/server/main/smack-check.cpp index 66b26f5..f78875f 100644 --- a/src/server/main/smack-check.cpp +++ b/src/server/main/smack-check.cpp @@ -61,54 +61,4 @@ int smack_check(void) #endif } -bool checkClientOnWhitelist(int sockfd, std::string whitelistPath) -{ - struct ucred cr; - socklen_t len = sizeof(struct ucred); - - // get client smack label from socket - if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cr, &len)) { - int err = errno; - LogError("getsockopt() failed: " << errnoToString(err)); - return false; - } - - std::string clientSmackLabel; - std::string path("/proc/" + std::to_string(cr.pid) + "/attr/current"); - std::ifstream file(path.c_str()); - if (!file.is_open()) { - LogError("failed to open " << path); - return false; - } - - std::getline(file, clientSmackLabel); - file.close(); - if (clientSmackLabel.empty()) - return false; - - // compare with whitelist labels - std::string line; - std::ifstream whitelistFile(whitelistPath.c_str()); - if (!whitelistFile.is_open()) { - LogError("failed to open " << whitelistPath); - return false; - } - - while (std::getline(whitelistFile, line)) { - if (line.empty()) - continue; - if (line.at(0) == COMMENT) - continue; - if (line.compare(clientSmackLabel) == 0) { - whitelistFile.close(); - LogDebug("Client " << clientSmackLabel << " is on whitelist"); - return true; - } - } - whitelistFile.close(); - LogError("Client " << clientSmackLabel << " is not on whitelist"); - - return false; -} - } // namespace AuthPasswd diff --git a/src/server/service/password.cpp b/src/server/service/password.cpp index 8a913fa..47aed68 100644 --- a/src/server/service/password.cpp +++ b/src/server/service/password.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -298,11 +298,12 @@ bool PasswordService::processOne(const ConnectionID &conn, MessageBuffer &buffer int tempHdr; Deserialization::Deserialize(buffer, tempHdr); PasswordHdrs hdr = static_cast(tempHdr); + auto& cynaraChecker = CynaraChecker::instance(); try { //try..catch for internal service errors, assigns error code for returning. switch (interfaceID) { case SOCKET_ID_CHECK: - if (!checkClientOnWhitelist(conn.sock, CLIENT_WHITELIST)) + if (!cynaraChecker.checkClientPrivilege(conn.sock, PLATFORM_PRIVILEGE)) retCode = AUTH_PASSWD_API_ERROR_ACCESS_DENIED; else if (socket_get_user(conn.sock, cur_user)) retCode = AUTH_PASSWD_API_ERROR_NO_USER; @@ -311,7 +312,7 @@ bool PasswordService::processOne(const ConnectionID &conn, MessageBuffer &buffer break; case SOCKET_ID_SET: - if (!checkClientOnWhitelist(conn.sock, CLIENT_WHITELIST)) + if (!cynaraChecker.checkClientPrivilege(conn.sock, PLATFORM_PRIVILEGE)) retCode = AUTH_PASSWD_API_ERROR_ACCESS_DENIED; else if (socket_get_user(conn.sock, cur_user)) retCode = AUTH_PASSWD_API_ERROR_NO_USER; @@ -320,14 +321,14 @@ bool PasswordService::processOne(const ConnectionID &conn, MessageBuffer &buffer break; case SOCKET_ID_RESET: - if (!checkClientOnWhitelist(conn.sock, ADMIN_CLIENT_WHITELIST)) + if (!cynaraChecker.checkClientPrivilege(conn.sock, PLATFORM_PRIVILEGE)) retCode = AUTH_PASSWD_API_ERROR_ACCESS_DENIED; else retCode = processResetFunctions(hdr, buffer); break; case SOCKET_ID_POLICY: - if (!checkClientOnWhitelist(conn.sock, ADMIN_CLIENT_WHITELIST)) + if (!cynaraChecker.checkClientPrivilege(conn.sock, PLATFORM_PRIVILEGE)) retCode = AUTH_PASSWD_API_ERROR_ACCESS_DENIED; else retCode = processPolicyFunctions(hdr, buffer); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 70ab2bd..f5ffc09 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,7 +25,7 @@ SET(TEST_SRCS main.cpp ${SERVER_PATH}/service/plugin-loader.cpp ${SERVER_PATH}/service/plugin-manager.cpp) -PKG_CHECK_MODULES(${TARGET_TEST}_DEP REQUIRED klay) +PKG_CHECK_MODULES(${TARGET_TEST}_DEP REQUIRED klay security-manager) INCLUDE_DIRECTORIES(SYSTEM ${${TARGET_TEST}_DEP_INCLUDE_DIRS} ${INCLUDE_PATH} diff --git a/tests/test-admin.cpp b/tests/test-admin.cpp index bdc10fe..efe275e 100644 --- a/tests/test-admin.cpp +++ b/tests/test-admin.cpp @@ -489,3 +489,57 @@ TESTCASE(T00206_max_num_seq) ret = auth_passwd_disable_policy(getuid()); TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); } + +TESTCASE(T00207_reset_passwd_privilege) +{ + auto reset_passwd_function = [] () -> int { + return auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + }; + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.settings.main", + AUTH_PASSWD_API_ERROR_ACCESS_DENIED, reset_passwd_function)); + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.Apps", + AUTH_PASSWD_API_SUCCESS, reset_passwd_function)); + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM, "", + AUTH_PASSWD_API_SUCCESS, reset_passwd_function)); + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM_PRIVILEGED, "", + AUTH_PASSWD_API_SUCCESS, reset_passwd_function)); +} + +TESTCASE(T00208_set_policy_privilege) +{ + auto set_policy_function = [] () -> int { + test::ScopedPolicy sp(test::create_policy_h(), auth_passwd_free_policy); + policy_h *policy = sp.get(); + + int ret = auth_passwd_set_user(policy, getuid()); + if (ret != AUTH_PASSWD_API_SUCCESS) + return ret; + ret = auth_passwd_set_max_attempts(policy, 10); + if (ret != AUTH_PASSWD_API_SUCCESS) + return ret; + + return auth_passwd_set_policy(policy);; + }; + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.settings.main", + AUTH_PASSWD_API_ERROR_ACCESS_DENIED, set_policy_function)); + + int ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.Apps", + AUTH_PASSWD_API_SUCCESS, set_policy_function)); + + ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM, "", + AUTH_PASSWD_API_SUCCESS, set_policy_function)); + + ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM_PRIVILEGED, "", + AUTH_PASSWD_API_SUCCESS, set_policy_function)); +} diff --git a/tests/test-client.cpp b/tests/test-client.cpp index 37b4986..e9e3637 100644 --- a/tests/test-client.cpp +++ b/tests/test-client.cpp @@ -305,3 +305,57 @@ TESTCASE(T00119_check_expire_policy) ret = auth_passwd_disable_policy(getuid()); TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); } + + +TESTCASE(T00120_check_passwd_privilege) +{ + auto check_passwd_function = [] () -> int { + return check_passwd(AUTH_PWD_NORMAL, default_pass); + }; + + int ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + + ret = auth_passwd_disable_policy(getuid()); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.settings.main", + AUTH_PASSWD_API_ERROR_ACCESS_DENIED, check_passwd_function)); + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.Apps", + AUTH_PASSWD_API_SUCCESS, check_passwd_function)); + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM, "", + AUTH_PASSWD_API_SUCCESS, check_passwd_function)); + + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM_PRIVILEGED, "", + AUTH_PASSWD_API_SUCCESS, check_passwd_function)); +} + +TESTCASE(T00121_set_passwd_privilege) +{ + auto set_passwd_function = [] () -> int { + sleep_for_retry_timeout(); + return auth_passwd_set_passwd(AUTH_PWD_NORMAL, default_pass, NULL); + }; + + int ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.settings.main", + AUTH_PASSWD_API_ERROR_ACCESS_DENIED, set_passwd_function)); + + ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_APP, "org.tizen.Apps", + AUTH_PASSWD_API_SUCCESS, set_passwd_function)); + + ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM, "", + AUTH_PASSWD_API_SUCCESS, set_passwd_function)); + + ret = auth_passwd_reset_passwd(AUTH_PWD_NORMAL, getuid(), default_pass); + TEST_EXPECT(AUTH_PASSWD_API_SUCCESS, ret); + TEST_EXPECT(true, test::run_in_process(SM_PROCESS_TYPE_SYSTEM_PRIVILEGED, "", + AUTH_PASSWD_API_SUCCESS, set_passwd_function)); +} diff --git a/tests/test-util.h b/tests/test-util.h index af531cc..c195cd0 100644 --- a/tests/test-util.h +++ b/tests/test-util.h @@ -24,6 +24,13 @@ #include #include +#include +#include + +#include +#include + +#include namespace test { @@ -31,4 +38,36 @@ policy_h *create_policy_h(); using ScopedPolicy = std::unique_ptr; +template +bool run_in_process(process_type ptype, const std::string& appId, int expected, Functor functor) +{ + pid_t p; + int stat; + + /* split this program into two processes */ + p = fork(); + + if( p == 0 ) { // child process is running + int ret = security_manager_set_identity(ptype, appId.c_str()); + + if(ret != SECURITY_MANAGER_SUCCESS) { + std::cout << "security_manager_set_identity() failed... ret=" << ret + << ", appId=" << appId << std::endl; + exit(2); // error case + } + ret = functor(); + if(ret != expected) { + std::cout << "The test in separated process failed..." + << "ptype=" << ptype << ", appId=" << appId + << ", expected=" << expected << ", actual=" << ret + << std::endl; + exit(2); // error case + } + exit(0); + } else { // parent process is runnin + wait(&stat); // wait for the child + return WIFEXITED(stat) & (WEXITSTATUS(stat) == 0); // check result from child + } +} + } // namespace test