Replace access control mechansm from white list to privilege. 74/317874/11
authorDongsun Lee <ds73.lee@samsung.com>
Thu, 9 Jan 2025 07:09:06 +0000 (16:09 +0900)
committerDongsun Lee <ds73.lee@samsung.com>
Mon, 13 Jan 2025 03:20:14 +0000 (12:20 +0900)
- 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

18 files changed:
CMakeLists.txt
conf/CMakeLists.txt [deleted file]
conf/admin-client-whitelist [deleted file]
conf/client-whitelist [deleted file]
packaging/auth-fw-test.manifest
packaging/auth-fw.spec
src/include/auth-passwd-admin.h
src/include/auth-passwd.h
src/server/CMakeLists.txt
src/server/main/include/privilege-check.h [new file with mode: 0644]
src/server/main/include/smack-check.h
src/server/main/privilege-check.cpp [new file with mode: 0644]
src/server/main/smack-check.cpp
src/server/service/password.cpp
tests/CMakeLists.txt
tests/test-admin.cpp
tests/test-client.cpp
tests/test-util.h

index ef4187907a0346648e73f8c905c065483e541539..c7f542711d8493611566fe52258cd804bb8dcfc9 100644 (file)
@@ -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 (file)
index 7178786..0000000
+++ /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 <jooseong.lee@samsung.com>
-#
-
-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 (file)
index 5e88c28..0000000
+++ /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 (file)
index a066890..0000000
+++ /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
index 94a93ea289849e3e631463bf46e97946b2d4baa2..a76fdbae7d915118498d7699ad37ccc98f8884f1 100644 (file)
@@ -2,7 +2,4 @@
        <request>
                <domain name="_" />
        </request>
-       <assign>
-               <filesystem path="/usr/bin/auth-fw-test" exec_label="System" />
-       </assign>
 </manifest>
index 1d733a229e909fc920f4e06017b6504077856532..aeb985bb66e7f3dc2bde0bd01669151e61cc6413 100644 (file)
@@ -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
index c260373b08aa25ca3ad66cda49e93d92f05da777..8f14a6020ae42ac01ce6f66df335b11e958650fa 100644 (file)
@@ -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.
  *
index 2fa6556f1a3b2ec0902183e463c3ec80a781520e..6e5f91356853d842838155e4359f45784536f9a0 100644 (file)
@@ -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.
  *
index cecadd3b3ed8a5eebca07d8e49874644698446fe..279d3f09d283ac9eb3a0f4f8e3ceceff684d3039 100644 (file)
@@ -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 (file)
index 0000000..532d314
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  Authentication password
+ *
+ *  Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Jooseong Lee <jooseong.lee@samsung.com>
+ *
+ *  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 <memory>
+#include <string>
+
+#include <cynara-client.h>
+
+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_
index 024c670ec6f5dbdae77e4f0837e16f0f6e192c5e..76b46b356bf0c3317bf0cda0efadd705e2649045 100644 (file)
@@ -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 (file)
index 0000000..562f93d
--- /dev/null
@@ -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 <dpl/log/log.h>
+
+#include <cynara-creds-socket.h>
+#include <cynara-session.h>
+
+
+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<char, string_free_deleter> user;
+       std::unique_ptr<char, string_free_deleter> client;
+       std::unique_ptr<char, string_free_deleter> 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
index 66b26f5deabb2d2abb41cb94f693680f70d8c6ac..f78875f6b01d67ed2df6a55827ced5cace88391e 100644 (file)
@@ -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
index 8a913fab21788b144281f26eb1888a62922dd6a2..47aed680c045b6e30cdc77ec24c94953970c0b38 100644 (file)
@@ -30,7 +30,7 @@
 #include <dpl/log/log.h>
 #include <dpl/serialization.h>
 
-#include <smack-check.h>
+#include <privilege-check.h>
 #include <user-check.h>
 
 #include <password.h>
@@ -298,11 +298,12 @@ bool PasswordService::processOne(const ConnectionID &conn, MessageBuffer &buffer
                int tempHdr;
                Deserialization::Deserialize(buffer, tempHdr);
                PasswordHdrs hdr = static_cast<PasswordHdrs>(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);
index 70ab2bdc0726124c1343a4ca2dbb7ef9225db1fc..f5ffc096120250774f2e3c09ad3a525221e5eedc 100644 (file)
@@ -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}
index bdc10feadc217d729d591f888dbd3a2c151130cb..efe275eb9154cc38c2d4c3c7d1dff353769a65c2 100644 (file)
@@ -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));
+}
index 37b4986bea0b596f653959c91f9a0dd3da8a0486..e9e3637f83438cbec263e008cc20068a6e5f57be 100644 (file)
@@ -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));
+}
index af531ccc96604f374bb0b6a2d5500312dc07d452..c195cd01c4b10776656e400dce58267eeda1b603 100644 (file)
 #include <auth-passwd-admin.h>
 
 #include <memory>
+#include <string>
+#include <iostream>
+
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <app-runtime.h>
 
 namespace test {
 
@@ -31,4 +38,36 @@ policy_h *create_policy_h();
 
 using ScopedPolicy = std::unique_ptr<policy_h, decltype(&auth_passwd_free_policy)>;
 
+template<typename Functor>
+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