Add security auth backend implementation 82/321982/11
authorDongik Lee <dongik.lee@samsung.com>
Wed, 19 Mar 2025 07:54:35 +0000 (16:54 +0900)
committerDongik Lee <dongik.lee@samsung.com>
Tue, 15 Apr 2025 09:12:35 +0000 (18:12 +0900)
Change-Id: Id1796f29d50bdd8f0996ef2843d620f7b980fb83

21 files changed:
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
packaging/hal-backend-security-auth.manifest [new file with mode: 0644]
packaging/hal-backend-security-auth.spec [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/hal_backend_security_auth.cpp [new file with mode: 0644]
src/hal_backend_security_auth.h [new file with mode: 0644]
src/hal_backend_security_auth_api.cpp [new file with mode: 0644]
src/util/error-description.cpp [new file with mode: 0644]
src/util/error-description.h [new file with mode: 0644]
src/util/exception.h [new file with mode: 0644]
src/util/fstream_accessors.h [new file with mode: 0644]
src/util/ipassword-file.h [new file with mode: 0644]
src/util/ipassword.cpp [new file with mode: 0644]
src/util/ipassword.h [new file with mode: 0644]
src/util/log.cpp [new file with mode: 0644]
src/util/log.h [new file with mode: 0644]
src/util/password-file-buffer.cpp [new file with mode: 0644]
src/util/password-file-buffer.h [new file with mode: 0644]
src/util/serialization.h [new file with mode: 0644]
src/util/symbol-visibility.h [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b149759
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2017 - 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.
+#
+
+PROJECT(hal-backend-security-auth LANGUAGES C CXX)
+CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
+
+INCLUDE(GNUInstallDirs)
+INCLUDE(CheckLibraryExists)
+
+IF(NOT CMAKE_BUILD_TYPE)
+       SET(CMAKE_BUILD_TYPE "RELEASE")
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+SET(CMAKE_C_FLAGS_DEBUG        "-std=c11 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
+SET(CMAKE_CXX_FLAGS_DEBUG      "-std=c++17 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
+SET(CMAKE_C_FLAGS_RELEASE      "-std=c11 -O2 -DNDEBUG")
+SET(CMAKE_CXX_FLAGS_RELEASE    "-std=c++17 -O2 -DNDEBUG")
+
+ADD_DEFINITIONS("-Werror -Wall -Wextra -Wno-deprecated-declarations")
+
+SET(CMAKE_POSITION_INDEPENDENT_CODE "True")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie")
+
+ADD_SUBDIRECTORY(src)
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..36123b0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,203 @@
+Copyright (c) 2000 - 2025 Samsung Electronics Co., Ltd. All rights reserved.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/packaging/hal-backend-security-auth.manifest b/packaging/hal-backend-security-auth.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/packaging/hal-backend-security-auth.spec b/packaging/hal-backend-security-auth.spec
new file mode 100644 (file)
index 0000000..0d206c0
--- /dev/null
@@ -0,0 +1,36 @@
+Name: hal-backend-security-auth
+Summary: Security Auth backend library
+Version: 1.0.0
+Release: 0
+Group: Security/Development
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source1001: hal-backend-security-auth.manifest
+BuildRequires: cmake
+BuildRequires: pkgconfig(hal-rootstrap)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description
+Security Auth backend library
+
+%global rw_data_dir %{?TZ_SYS_DATA:%TZ_SYS_DATA/%name}%{!?TZ_SYS_DATA:/opt/data/auth-fw}
+
+%prep
+%setup -q
+cp -a %{SOURCE1001} .
+
+%build
+%cmake ./ -DHAL_LIB_DIR=%{_hal_libdir} \
+        -DRW_DATA_DIR:PATH=%{rw_data_dir} \
+        -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:Release}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%files
+%manifest hal-backend-security-auth.manifest
+%license LICENSE
+%{_hal_libdir}/lib%{name}.so*
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5c7d063
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (c) 2017 - 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.
+#
+
+PROJECT(hal-backend-security-auth LANGUAGES C CXX)
+SET(PROJECT_VERSION "1.0.0")
+
+SET(_LIB_VERSION_ "${PROJECT_VERSION}")
+SET(_LIB_SOVERSION_ "0")
+
+FIND_PACKAGE(PkgConfig REQUIRED)
+PKG_CHECK_MODULES(ROOTSTRAP REQUIRED hal-rootstrap)
+
+INCLUDE_DIRECTORIES(SYSTEM ${ROOTSTRAP_INCLUDE_DIRS})
+LINK_DIRECTORIES(${ROOTSTRAP_LIBRARY_DIRS})
+
+FILE(GLOB SRCS ${SRCS} util/*.cpp)
+FILE(GLOB SRCS ${SRCS} *.cpp)
+
+ADD_DEFINITIONS("-DRW_DATA_DIR=\"${RW_DATA_DIR}\"")
+
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${ROOTSTRAP_LIBRARIES} -lcrypto -lssl -ldlog -ldl)
+
+SET_TARGET_PROPERTIES(${PROJECT_NAME}
+       PROPERTIES
+       VERSION ${_LIB_VERSION_}
+       SOVERSION ${_LIB_SOVERSION_}
+       VISIBILITY_INLINES_HIDDEN TRUE
+       C_VISIBILITY_PRESET hidden
+       CXX_VISIBILITY_PRESET hidden)
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${HAL_LIB_DIR} COMPONENT RuntimeLibraries)
diff --git a/src/hal_backend_security_auth.cpp b/src/hal_backend_security_auth.cpp
new file mode 100644 (file)
index 0000000..22fbf17
--- /dev/null
@@ -0,0 +1,592 @@
+/******************************************************************
+ * Copyright 2017 - 2025 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+#include <chrono>
+#include <fstream>
+#include <algorithm>
+#include <fcntl.h>
+#include <ratio>
+#include <string>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <hal/hal-security-auth-error.h>
+
+#include "util/ipassword.h"
+#include "util/log.h"
+#include "util/fstream_accessors.h"
+#include "util/error-description.h"
+#include "util/password-file-buffer.h"
+#include "hal_backend_security_auth.h"
+
+namespace {
+       const unsigned int PASSWORD_INFINITE_ATTEMPT_COUNT = 0;
+       const unsigned int PASSWORD_INFINITE_EXPIRATION_DAYS = 0;
+       const std::string PASSWORD_FILE = "/password";
+       const std::string OLD_VERSION_PASSWORD_FILE = "/password.old";
+       const std::string ATTEMPT_FILE = "/attempt";
+       const double RETRY_TIMEOUT = 0.5;
+       const mode_t FILE_MODE = S_IRUSR | S_IWUSR;
+       const unsigned int CURRENT_FILE_VERSION = 5;
+       const unsigned int PASSWORD_API_NO_EXPIRATION = 0xFFFFFFFF;
+} // namespace anonymous
+
+hal_backend_security_auth::hal_backend_security_auth(uid_t user_id, hal_security_auth_password_type_e password_type):
+                       m_user(user_id),
+                       m_passwordType(password_type),
+                       m_passwordCurrent(new NoPassword()),
+                       m_maxHistorySize(0),
+                       m_expireTime(PASSWORD_INFINITE_EXPIRATION_DAYS),
+                       m_expireTimeLeft(PASSWORD_INFINITE_EXPIRATION_TIME),
+                       m_passwordActive(false),
+                       m_passwordRcvActive(false),
+                       m_attempt(0)
+{
+       m_maxAttempt = PASSWORD_INFINITE_ATTEMPT_COUNT;
+
+       LOGD("hal_backend_security_auth constructor user_id : "<< user_id << ", password_type : " << password_type);
+       LOGD(" default value max_attempt : "<< m_maxAttempt << ", max_history_size : " << m_maxHistorySize);
+       LOGD("  expire_time : "<< m_expireTime << ", expire_time_left : " << m_expireTimeLeft << ", password_is_active : " << m_passwordActive);
+       LOGD("  password_is_rcv_active : "<< m_passwordRcvActive << ", attempt : " << m_attempt);
+
+       std::string userDir = create_dir(RW_DATA_DIR, m_user);
+
+       if (!dir_exists(RW_DATA_DIR)) {
+               if (mkdir(RW_DATA_DIR, 0700)) {
+                       LOGE(" Failed to create directory for files. Error: " << errnoToString());
+               }
+       }
+
+       if (!dir_exists(userDir.c_str())) {
+               if (mkdir(userDir.c_str(), 0700)) {
+                       LOGE(" Failed to create directory for files. Error: " << errnoToString());
+               }
+       }
+
+       prepare_password_file();
+       prepare_attempt_file();
+       reset_timer();
+}
+
+bool hal_backend_security_auth::file_exists(const std::string &filename) const
+{
+       struct stat buf;
+       return ((stat(filename.c_str(), &buf) == 0));
+}
+
+bool hal_backend_security_auth::dir_exists(const std::string &dirpath) const
+{
+       struct stat buf;
+       return ((stat(dirpath.c_str(), &buf) == 0) && (((buf.st_mode) & S_IFMT) == S_IFDIR));
+}
+
+std::string hal_backend_security_auth::create_dir(const std::string &dir, unsigned int user) const
+{
+       std::string User = std::to_string(user);
+       return dir + "/" + User;
+}
+
+void hal_backend_security_auth::reset_state()
+{
+       m_maxAttempt = PASSWORD_INFINITE_ATTEMPT_COUNT;
+       m_maxHistorySize = 0;
+       m_expireTime = PASSWORD_INFINITE_EXPIRATION_DAYS;
+       m_expireTimeLeft = PASSWORD_INFINITE_EXPIRATION_TIME;
+       m_passwordRcvActive = false;
+       m_passwordActive = false;
+       m_passwordCurrent.reset(new NoPassword());
+}
+
+
+void hal_backend_security_auth::reset_timer()
+{
+       m_retryTimerStart = ClockType::now();
+       m_retryTimerStart -= TimeDiff(RETRY_TIMEOUT);
+}
+
+bool hal_backend_security_auth::load_memory_from_file(const std::string& passwdFilePath)
+{
+       struct stat fileStat;
+
+       if (stat(passwdFilePath.c_str(), &fileStat) != 0)
+               return false;
+
+       PasswordFileBuffer pwdBuffer;
+       pwdBuffer.Load(passwdFilePath);
+       unsigned int fileVersion = 0;
+       Deserialization::Deserialize(pwdBuffer, fileVersion);
+
+       switch (fileVersion) {
+       case 1:
+       case 2:
+       case 3:
+               Deserialization::Deserialize(pwdBuffer, m_maxAttempt);
+               Deserialization::Deserialize(pwdBuffer, m_maxHistorySize);
+               Deserialization::Deserialize(pwdBuffer, m_expireTimeLeft);
+               Deserialization::Deserialize(pwdBuffer, m_passwordActive);
+               Deserialization::Deserialize(pwdBuffer, m_passwordCurrent);
+               Deserialization::Deserialize(pwdBuffer, m_passwordHistory);
+               m_expireTime = PASSWORD_INFINITE_EXPIRATION_DAYS;
+               m_passwordRcvActive = false;
+               m_passwordType = hal_security_auth_password_type_e::HAL_SECURITY_AUTH_PASSWORD_NORMAL; // Normal
+               // update file to new format
+               write_memory_to_file(m_user);
+               break;
+       case 4:
+               Deserialization::Deserialize(pwdBuffer, m_maxAttempt);
+               Deserialization::Deserialize(pwdBuffer, m_maxHistorySize);
+               Deserialization::Deserialize(pwdBuffer, m_expireTime);
+               Deserialization::Deserialize(pwdBuffer, m_expireTimeLeft);
+               Deserialization::Deserialize(pwdBuffer, m_passwordRcvActive);
+               Deserialization::Deserialize(pwdBuffer, m_passwordActive);
+               Deserialization::Deserialize(pwdBuffer, m_passwordCurrent);
+               Deserialization::Deserialize(pwdBuffer, m_passwordHistory);
+               m_passwordType = hal_security_auth_password_type_e::HAL_SECURITY_AUTH_PASSWORD_NORMAL; // Normal
+               break;
+       default:
+               LOGE("Invaild password version: " << fileVersion);
+       }
+
+       LOGD("loadMemoryFromFile: File=" << passwdFilePath <<
+                ":: User: " << m_user << ", loaded max_att: " << m_maxAttempt <<
+               ", history_size: " << m_maxHistorySize << ", m_expireTime: " <<
+               m_expireTime << ", m_expireTimeLeft: " << m_expireTimeLeft <<
+               ", isActive: " << m_passwordActive << ", isRcvActive: " <<
+               m_passwordRcvActive<< ", m_passwordType: " << m_passwordType);
+       return true;
+}
+
+void hal_backend_security_auth::prepare_password_file()
+{
+       std::string pwdFile = create_dir(RW_DATA_DIR, m_user) + PASSWORD_FILE;
+       std::string oldVersionPwdFile = create_dir(RW_DATA_DIR, m_user) + OLD_VERSION_PASSWORD_FILE;
+
+       // check if password file exists
+       if (!file_exists(pwdFile)) {
+               // if old format file exist - load it
+               if (load_memory_from_file(oldVersionPwdFile)) {
+                       // save in new format
+                       write_memory_to_file(m_user);
+
+                       // and remove old file
+                       if (remove(oldVersionPwdFile.c_str())) {
+                               LOGE("Failed to remove file" << oldVersionPwdFile <<
+                                                " Error: " << errnoToString());
+                       }
+                       return;
+               }
+
+               LOGE("PWD_DBG not found " << m_user << " password file. Creating.");
+               //create file
+               write_memory_to_file(m_user);
+       } else {     //if file exists, load data
+               LOGE("PWD_DBG found " << m_user << " password file. Opening.");
+
+               try {
+                       load_memory_from_file(oldVersionPwdFile);
+               } catch (...) {
+                       LOGE("Invalid " << pwdFile << " file format");
+                       reset_state();
+                       write_memory_to_file(m_user);
+               }
+       }
+}
+
+void hal_backend_security_auth::prepare_attempt_file()
+{
+       std::string attemptFile = create_dir(RW_DATA_DIR, m_user) + ATTEMPT_FILE;
+
+       // check if attempt file exists
+       if (!file_exists(attemptFile)) {
+               LOGE("PWD_DBG not found " << m_user << " attempt file. Creating.");
+               write_attempt_to_file(m_user);
+       } else {
+               LOGE("PWD_DBG found " << m_user << " attempt file. Opening.");
+               std::ifstream AttemptFile(attemptFile);
+
+               if (!AttemptFile) {
+                       LOGE("Failed to open " << m_user << " attempt file.");
+                       // ignore error
+                       return;
+               }
+
+               AttemptFile.read(reinterpret_cast<char *>(&m_attempt), sizeof(unsigned int));
+
+               if (!AttemptFile) {
+                       LOGE("Failed to read " << m_user << " attempt count.");
+                       // ignore error
+                       reset_attempt(m_user);
+               }
+       }
+}
+
+int hal_backend_security_auth::write_memory_to_file(uid_t user_id) const
+{
+       LOGD("hal_backend_security_auth::write_memory_to_file");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       std::string pwdFile = create_dir(RW_DATA_DIR, m_user) + PASSWORD_FILE;
+       PasswordFileBuffer pwdBuffer;
+       LOGD(" user: " << m_user << ", max_attempt: " << m_maxAttempt <<
+               ", history_size: " << m_maxHistorySize << ", m_expireTime: " <<
+               m_expireTime << ", m_expireTimeLeft: " << m_expireTimeLeft <<
+               ", isActive: " << m_passwordActive << ", isRcvActive: " <<
+               m_passwordRcvActive << ", m_passwordType: " << m_passwordType);
+       //serialize password attributes
+       Serialization::Serialize(pwdBuffer, CURRENT_FILE_VERSION);
+       Serialization::Serialize(pwdBuffer, m_maxAttempt);
+       Serialization::Serialize(pwdBuffer, m_maxHistorySize);
+       Serialization::Serialize(pwdBuffer, m_expireTime);
+       Serialization::Serialize(pwdBuffer, m_expireTimeLeft);
+       Serialization::Serialize(pwdBuffer, m_passwordRcvActive);
+       Serialization::Serialize(pwdBuffer, m_passwordActive);
+       Serialization::Serialize(pwdBuffer, m_passwordCurrent);
+       Serialization::Serialize(pwdBuffer, m_passwordHistory);
+       Serialization::Serialize(pwdBuffer, m_passwordType);
+
+       pwdBuffer.Save(pwdFile);
+       if (chmod(pwdFile.c_str(), FILE_MODE)) {
+               LOGE(" Failed to chmod for " << pwdFile << " Error: " << errnoToString());
+       }
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::write_attempt_to_file(uid_t user_id) const
+{
+       LOGD("hal_backend_security_auth::write_attempt_to_file");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       std::string attemptFile = create_dir(RW_DATA_DIR, m_user) + ATTEMPT_FILE;
+       std::ofstream AttemptFile(attemptFile, std::ofstream::trunc);
+
+       if (!AttemptFile.good()) {
+               LOGE(" Failed to open " << m_user << " attempt file.");
+       }
+
+       AttemptFile.write(reinterpret_cast<const char *>(&m_attempt), sizeof(unsigned int));
+
+       if (!AttemptFile) {
+               LOGE(" Failed to write " << m_user << " attempt count.");
+       }
+
+       AttemptFile.flush();
+       if (::fsync(FstreamAccessors<std::ofstream>::GetFd(AttemptFile)) != 0)
+               LOGE(" Failed to synchronize a file's state.");
+       AttemptFile.close();
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::set_password(uid_t user_id, const char* password)
+{
+       LOGD("hal_backend_security_auth::set_password");
+       if(user_id != m_user || password == nullptr)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       if (password[0] == '\0') {
+               m_passwordCurrent.reset(new NoPassword());
+               m_passwordActive = false;
+       } else {
+               std::string password_str = std::string(password);
+               m_passwordCurrent.reset(new SHA256Password(password_str));
+               //put current password to history
+               m_passwordHistory.push_front(m_passwordCurrent);
+
+               //erase last password if we exceed max history size
+               if (m_passwordHistory.size() > m_maxHistorySize)
+                       m_passwordHistory.pop_back();
+
+               m_passwordActive = true;
+       }
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::check_password(uid_t user_id, const char* password)
+{
+       LOGD("hal_backend_security_auth::check_password");
+       if(user_id != m_user || password == nullptr)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       return m_passwordCurrent->match(password) ? AUTH_PASSWD_API_SUCCESS : AUTH_PASSWD_API_ERROR_PASSWORD_MISMATCH;
+}
+
+int hal_backend_security_auth::set_max_history_size(uid_t user_id, unsigned int history_size)
+{
+       LOGD("hal_backend_security_auth::set_max_history_size");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       // put current password in history
+       if (m_maxHistorySize == 0 && history_size > 0)
+               m_passwordHistory.push_front(m_passwordCurrent);
+
+       //setting history should be independent from password being set
+       m_maxHistorySize = history_size;
+
+       while (m_passwordHistory.size() > history_size)
+               m_passwordHistory.pop_back();
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::get_max_history_size(uid_t user_id, unsigned int *history_size) const
+{
+       LOGD("hal_backend_security_auth::get_max_history_size");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       *history_size = m_maxHistorySize;
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::get_expire_time(uid_t user_id, unsigned int *expire_time) const
+{
+       LOGD("hal_backend_security_auth::get_expire_time");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       *expire_time = m_expireTime;
+       LOGE(" *expire_time : "<<m_expireTime);
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::set_expire_time(uid_t user_id, unsigned int expire_time)
+{
+       LOGD("hal_backend_security_auth::set_expire_time m_expireTime: " << m_expireTime);
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       m_expireTime = expire_time;
+       LOGD(" expire_time : "<< m_expireTime);
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::get_attempt(uid_t user_id, unsigned int *attempt) const
+{
+       LOGD("hal_backend_security_auth::get_attempt");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       *attempt = m_attempt;
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::set_expire_time_left(uid_t user_id, unsigned int expire_time_left)
+{
+       LOGD("hal_backend_security_auth::set_expire_time_left");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       m_expireTimeLeft = expire_time_left;
+       LOGD(" expire_time_left : "<<m_expireTimeLeft);
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::get_expire_time_left(uid_t user_id, unsigned int *expire_time_left) const
+{
+       LOGD("hal_backend_security_auth::get_expire_time_left");
+       //calculate left secs by the time of password expiration
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       if (m_expireTimeLeft != PASSWORD_INFINITE_EXPIRATION_TIME) {
+               LOGD(" not eq m_expireTimeLeft : " << m_expireTimeLeft << " PIET : " << PASSWORD_INFINITE_EXPIRATION_TIME);
+
+               time_t timeLeft = m_expireTimeLeft - time(NULL);
+               *expire_time_left = (timeLeft < 0) ? 0 : static_cast<unsigned int>(timeLeft);
+               LOGD(" not eq expire_time_left : " << *expire_time_left << " timeLeft : " << timeLeft);
+
+       } else {
+               *expire_time_left = PASSWORD_API_NO_EXPIRATION;
+               LOGD(" expire_time_left : " << *expire_time_left);
+
+       }
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::reset_attempt(uid_t user_id)
+{
+       LOGD("hal_backend_security_auth::reset_attempt");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       m_attempt = 0;
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::increment_attempt(uid_t user_id)
+{
+       LOGD("hal_backend_security_auth::increment_attempt");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       m_attempt++;
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::get_max_attempt(uid_t user_id, unsigned int *max_attempt) const
+{
+       LOGD("hal_backend_security_auth::get_max_attempt");
+
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       *max_attempt = m_maxAttempt;
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::set_max_attempt(uid_t user_id, unsigned int max_attempt)
+{
+       LOGD("hal_backend_security_auth::set_max_attempt");
+
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       m_maxAttempt = max_attempt;
+
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::is_password_active(uid_t user_id) const
+{
+       LOGD("hal_backend_security_auth::is_password_active");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       return m_passwordActive ? AUTH_PASSWD_API_SUCCESS : AUTH_PASSWD_API_ERROR_STATUS;
+}
+
+int hal_backend_security_auth::is_password_reused(uid_t user_id, const char* password) const
+{
+       LOGD("hal_backend_security_auth::is_password_reused");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       LOGD(" user_id : "<< m_user << " history_size: " <<
+                                               m_passwordHistory.size() << ", max_history_size: " << m_maxHistorySize);
+
+       // go through history and check if password existed earlier
+       if (std::any_of(
+                       m_passwordHistory.begin(),
+                       m_passwordHistory.end(),
+                       [&password](const IPasswordPtr & pwd) {
+                               return pwd->match(password);
+                       })) {
+               LOGE(" password match!");
+               return AUTH_PASSWD_API_SUCCESS;
+       }
+
+       LOGE(" Failed isPasswordReused: No passwords match");
+       return AUTH_PASSWD_API_ERROR_STATUS;
+}
+
+int hal_backend_security_auth::check_expiration(uid_t user_id) const
+{
+       LOGD("hal_backend_security_auth::check_expiration");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       LOGD(" m_expireTimeLeft : " << m_expireTimeLeft << " PIET : "<< PASSWORD_INFINITE_EXPIRATION_TIME << " time: " << time(NULL) << " m_eTLeft : " << m_expireTimeLeft);
+       return ((m_expireTimeLeft != PASSWORD_INFINITE_EXPIRATION_TIME) && (time(NULL) > m_expireTimeLeft)) ? AUTH_PASSWD_API_ERROR_PASSWORD_EXPIRED : AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::check_attempt_exceeded(uid_t user_id) const
+{
+       LOGD("hal_backend_security_auth::check_attempt_exceeded");
+       LOGD(" m_maxAttempt : " << m_maxAttempt << " P_I_A_C : " << PASSWORD_INFINITE_ATTEMPT_COUNT << " m_attempt : " << m_attempt);
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       return ((m_maxAttempt != PASSWORD_INFINITE_ATTEMPT_COUNT) && (m_attempt > m_maxAttempt)) ? AUTH_PASSWD_API_ERROR_PASSWORD_MAX_ATTEMPTS_EXCEEDED : AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::is_ignore_period(uid_t user_id) const
+{
+       LOGD("hal_backend_security_auth::is_ignore_period");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       TimePoint retryTimerStop = ClockType::now();
+       TimeDiff diff = retryTimerStop - m_retryTimerStart;
+
+       m_retryTimerStart = retryTimerStop;
+       return (diff.count() < RETRY_TIMEOUT) ? AUTH_PASSWD_API_SUCCESS : AUTH_PASSWD_API_ERROR_PASSWORD_RETRY_TIMER;
+}
+
+int hal_backend_security_auth::is_history_active(uid_t user_id) const
+{
+       LOGD("hal_backend_security_auth::is_history_active");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       return (m_maxHistorySize != 0) ? AUTH_PASSWD_API_SUCCESS : AUTH_PASSWD_API_ERROR_STATUS;
+}
+
+int hal_backend_security_auth::get_password_type(uid_t user_id,
+                                                                                                hal_security_auth_password_type_e *password_type) const
+{
+       LOGD("hal_backend_security_auth::get_password_type");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       *password_type = m_passwordType;
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+int hal_backend_security_auth::set_password_type(uid_t user_id,
+                                                                                                hal_security_auth_password_type_e password_type)
+{
+       LOGD("hal_backend_security_auth::set_password_type");
+       if(user_id != m_user)
+               return AUTH_PASSWD_API_ERROR_INPUT_PARAM;
+       m_passwordType = password_type;
+       return AUTH_PASSWD_API_SUCCESS;
+}
+
+uid_t hal_backend_security_auth::get_user_id() const
+{
+       LOGD("hal_backend_security_auth::get_user_id");
+       uid_t user_id = getuid();
+       return user_id;
+}
+
+hal_backend_security_auth::~hal_backend_security_auth()
+{
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static std::map<uid_t, hal_backend_security_auth*> hal_backend_security_auth_instance_map;
+
+hal_backend_security_auth* get_hal_backend_security_auth_instance(uid_t user_id, hal_security_auth_password_type_e password_type)
+{
+       hal_security_auth_password_type_e current_password_type;
+       auto itAuth = hal_backend_security_auth_instance_map.find(user_id);
+       LOGD("get_hal_backend_security_auth_instance");
+
+       if (itAuth != hal_backend_security_auth_instance_map.end()){
+               hal_backend_security_auth *authInstance = itAuth->second;
+               authInstance->get_password_type(user_id, &current_password_type);
+               if(current_password_type == password_type){
+                       LOGD(" found the user and the same type");
+                       return authInstance;
+               }
+               else{
+                       authInstance->set_password_type(user_id, password_type);
+                       LOGD(" found the user and the diffent type, so changed.");
+                       return authInstance;
+               }
+       }
+
+       LOGD(" Not found and created a new instance");
+       hal_backend_security_auth* new_security_auth = new hal_backend_security_auth(user_id,password_type);
+       hal_backend_security_auth_instance_map[user_id] = new_security_auth;
+       return new_security_auth;
+}
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/src/hal_backend_security_auth.h b/src/hal_backend_security_auth.h
new file mode 100644 (file)
index 0000000..b92b97e
--- /dev/null
@@ -0,0 +1,135 @@
+/******************************************************************
+ * Copyright 2017 - 2025 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+#ifndef BACKEND_HAL_BACKEND_SECURITY_AUTH_H_
+#define BACKEND_HAL_BACKEND_SECURITY_AUTH_H_
+
+#include <string>
+#include <map>
+#include <memory>
+#include <chrono>
+#include <time.h>
+#include <hal/hal-security-auth-interface.h>
+#include <hal/hal-security-auth-types.h>
+
+#include "util/ipassword-file.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+class hal_backend_security_auth : public IPasswordFile {
+       public:
+               hal_backend_security_auth(uid_t user_id, hal_security_auth_password_type_e password_type);
+               ~hal_backend_security_auth();
+
+               hal_backend_security_auth(const hal_backend_security_auth&) = delete;
+               hal_backend_security_auth& operator=(const hal_backend_security_auth&) = delete;
+
+               int write_memory_to_file(uid_t user_id) const override;
+
+               int write_attempt_to_file(uid_t user_id) const override;
+
+               int set_password(uid_t user_id, const char* password) override;
+
+               int check_password(uid_t user_id, const char* password) override;
+
+               int set_max_history_size(uid_t user_id, unsigned int history_size) override;
+
+               int get_max_history_size(uid_t user_id, unsigned int *history_size) const override;
+
+               int get_expire_time(uid_t user_id, unsigned int *expire_time) const override;
+
+               int set_expire_time(uid_t user_id, unsigned int expire_time) override;
+
+               int get_attempt(uid_t user_id, unsigned int *attempt) const override;
+
+               int reset_attempt(uid_t user_id) override;
+
+               int increment_attempt(uid_t user_id) override;
+
+               int get_max_attempt(uid_t user_id, unsigned int *max_attempt) const override;
+
+               int set_max_attempt(uid_t user_id, unsigned int max_attempt) override;
+
+               int get_expire_time_left(uid_t user_id, unsigned int *expire_time_left) const override;
+
+               int set_expire_time_left(uid_t user_id, unsigned int expire_time_left) override;
+
+               int is_password_active(uid_t user_id) const override;
+
+               int is_password_reused(uid_t user_id, const char* password)const override;
+
+               int check_expiration(uid_t user_id) const override;
+
+               int check_attempt_exceeded(uid_t user_id) const override;
+
+               int is_ignore_period(uid_t user_id) const override;
+
+               int is_history_active(uid_t user_id) const override;
+
+               int get_password_type(uid_t user_id, hal_security_auth_password_type_e *password_type) const override;
+
+               uid_t get_user_id() const override;
+
+               int set_password_type(uid_t user_id, hal_security_auth_password_type_e password_type);
+
+               int reset_password(uid_t user_id);
+
+       private:
+               hal_security_auth_password_type_e       password_type;
+               uid_t user_id;
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7))
+               typedef std::chrono::steady_clock ClockType;
+#else
+               typedef std::chrono::monotonic_clock ClockType;
+#endif
+               typedef std::chrono::duration<double> TimeDiff;
+               typedef std::chrono::time_point<ClockType, TimeDiff> TimePoint;
+
+               bool load_memory_from_file(const std::string &passwdFilePath);
+               void reset_timer();
+               void prepare_password_file();
+               void prepare_attempt_file();
+               void reset_state();
+               bool file_exists(const std::string &filename) const;
+               bool dir_exists(const std::string &dirpath) const;
+               unsigned int get_max_history_size() const;
+               std::string create_dir(const std::string &dir, unsigned int user) const;
+
+               mutable TimePoint m_retryTimerStart;
+
+               const uid_t m_user;
+               hal_security_auth_password_type_e m_passwordType;
+               IPasswordPtr m_passwordCurrent;
+               PasswordList m_passwordHistory;
+               unsigned int m_maxAttempt;
+               unsigned int m_maxHistorySize;
+               unsigned int m_expireTime;
+               time_t       m_expireTimeLeft;
+               bool         m_passwordActive;
+               bool         m_passwordRcvActive;
+               unsigned int m_attempt;
+};
+
+hal_backend_security_auth* get_hal_backend_security_auth_instance(uid_t user_id, hal_security_auth_password_type_e password_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BACKEND_HAL_BACKEND_SECURITY_AUTH_H_ */
\ No newline at end of file
diff --git a/src/hal_backend_security_auth_api.cpp b/src/hal_backend_security_auth_api.cpp
new file mode 100644 (file)
index 0000000..254a59b
--- /dev/null
@@ -0,0 +1,206 @@
+/******************************************************************
+ * Copyright 2019 - 2025 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+#include <hal/hal-common-interface.h>
+
+#include "util/log.h"
+#include "hal_backend_security_auth.h"
+
+#define EXPORT __attribute__ ((visibility("default")))
+
+static hal_backend_security_auth *g_auth_instance = nullptr;
+
+int security_auth_create_password_file(uid_t user_id,
+                                                                 hal_security_auth_password_type_e password_type)
+{
+       LOGD("security_auth_create_password_file");
+       g_auth_instance = get_hal_backend_security_auth_instance(user_id, password_type);
+       return g_auth_instance ? 0: -ENOTSUP;
+}
+
+int security_auth_write_memory_to_file(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->write_memory_to_file(user_id) : -ENOTSUP;
+}
+
+int security_auth_write_attempt_to_file(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->write_attempt_to_file(user_id) : -ENOTSUP;
+}
+
+int security_auth_set_password(uid_t user_id, const char* password)
+{
+       return g_auth_instance ? g_auth_instance->set_password(user_id, password) : -ENOTSUP;
+}
+
+int security_auth_check_password(uid_t user_id, const char* password)
+{
+       return g_auth_instance ? g_auth_instance->check_password(user_id, password) : -ENOTSUP;
+}
+
+int security_auth_set_max_history_size(uid_t user_id, unsigned int history_size)
+{
+       return g_auth_instance ? g_auth_instance->set_max_history_size(user_id, history_size) : -ENOTSUP;
+}
+
+int security_auth_get_max_history_size(uid_t user_id, unsigned int *history_size)
+{
+       return g_auth_instance ? g_auth_instance->get_max_history_size(user_id, history_size) : -ENOTSUP;
+}
+
+int security_auth_get_expire_time(uid_t user_id, unsigned int *expire_time)
+{
+       return g_auth_instance ? g_auth_instance->get_expire_time(user_id, expire_time) : -ENOTSUP;
+}
+
+int security_auth_set_expire_time(uid_t user_id, unsigned int expire_time)
+{
+       return g_auth_instance ? g_auth_instance->set_expire_time(user_id, expire_time) : -ENOTSUP;
+}
+
+int security_auth_get_attempt(uid_t user_id, unsigned int *attempt)
+{
+       return g_auth_instance ? g_auth_instance->get_attempt(user_id, attempt) : -ENOTSUP;
+}
+
+int security_auth_reset_attempt(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->reset_attempt(user_id) : -ENOTSUP;
+}
+
+int security_auth_increment_attempt(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->increment_attempt(user_id) : -ENOTSUP;
+}
+
+int security_auth_get_max_attempt(uid_t user_id, unsigned int *max_attempt)
+{
+       return g_auth_instance ? g_auth_instance->get_max_attempt(user_id, max_attempt) : -ENOTSUP;
+}
+
+int security_auth_set_max_attempt(uid_t user_id, unsigned int max_attempt)
+{
+       return g_auth_instance ? g_auth_instance->set_max_attempt(user_id, max_attempt) : -ENOTSUP;
+}
+
+int security_auth_get_expire_time_left(uid_t user_id, unsigned int *expire_time_left)
+{
+       return g_auth_instance ? g_auth_instance->get_expire_time_left(user_id, expire_time_left) : -ENOTSUP;
+}
+
+int security_auth_set_expire_time_left(uid_t user_id, unsigned int expire_time_left)
+{
+       return g_auth_instance ? g_auth_instance->set_expire_time_left(user_id, expire_time_left) : -ENOTSUP;
+}
+
+int security_auth_is_password_active(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->is_password_active(user_id) : -ENOTSUP;
+}
+
+int security_auth_is_password_reused(uid_t user_id, const char* password)
+{
+       return g_auth_instance ? g_auth_instance->is_password_reused(user_id, password) : -ENOTSUP;
+}
+
+int security_auth_check_expiration(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->check_expiration(user_id) : -ENOTSUP;
+}
+
+int security_auth_check_attempt_exceeded(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->check_attempt_exceeded(user_id) : -ENOTSUP;
+}
+
+int security_auth_is_ignore_period(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->is_ignore_period(user_id) : -ENOTSUP;
+}
+
+int security_auth_is_history_active(uid_t user_id)
+{
+       return g_auth_instance ? g_auth_instance->is_history_active(user_id) : -ENOTSUP;
+}
+
+int security_auth_get_password_type(uid_t user_id,
+                                                          hal_security_auth_password_type_e *password_type)
+{
+       return g_auth_instance ? g_auth_instance->get_password_type(user_id, password_type) : -ENOTSUP;
+}
+
+static int security_auth_backend_init(void **data)
+{
+       hal_backend_security_auth_funcs *security_auth_funcs;
+
+       if (!data) {
+               return -EINVAL;
+    }
+
+       security_auth_funcs = *(hal_backend_security_auth_funcs **)data;
+       if (!security_auth_funcs)
+               return -EINVAL;
+
+       security_auth_funcs->create_password_file  = security_auth_create_password_file;
+       security_auth_funcs->write_memory_to_file  = security_auth_write_memory_to_file;
+       security_auth_funcs->write_attempt_to_file  = security_auth_write_attempt_to_file;
+       security_auth_funcs->set_password  = security_auth_set_password;
+       security_auth_funcs->check_password  = security_auth_check_password;
+       security_auth_funcs->set_max_history_size  = security_auth_set_max_history_size;
+       security_auth_funcs->get_max_history_size  = security_auth_get_max_history_size;
+       security_auth_funcs->get_expire_time  = security_auth_get_expire_time;
+       security_auth_funcs->set_expire_time  = security_auth_set_expire_time;
+       security_auth_funcs->get_attempt  = security_auth_get_attempt;
+       security_auth_funcs->reset_attempt  = security_auth_reset_attempt;
+       security_auth_funcs->increment_attempt  = security_auth_increment_attempt;
+       security_auth_funcs->get_max_attempt  = security_auth_get_max_attempt;
+       security_auth_funcs->get_expire_time_left  = security_auth_get_expire_time_left;
+       security_auth_funcs->set_expire_time_left  = security_auth_set_expire_time_left;
+       security_auth_funcs->set_max_attempt = security_auth_set_max_attempt;
+       security_auth_funcs->check_attempt_exceeded = security_auth_check_attempt_exceeded;
+       security_auth_funcs->is_password_active = security_auth_is_password_active;
+       security_auth_funcs->is_history_active = security_auth_is_history_active;
+       security_auth_funcs->is_password_reused = security_auth_is_password_reused;
+       security_auth_funcs->check_expiration = security_auth_check_expiration;
+       security_auth_funcs->is_ignore_period = security_auth_is_ignore_period;
+       security_auth_funcs->get_password_type = security_auth_get_password_type;
+
+       return 0;
+}
+
+static int security_auth_backend_exit(void *data)
+{
+       (void)data;
+       return 0;
+}
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+hal_backend EXPORT hal_backend_security_auth_data = {
+       .name = "backend_security_auth",
+       .vendor = "Samsung",
+       .init  = security_auth_backend_init,
+       .exit  = security_auth_backend_exit,
+       .major_version = 1,
+       .minor_version = 0,
+};
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/src/util/error-description.cpp b/src/util/error-description.cpp
new file mode 100644 (file)
index 0000000..39b6392
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2000 - 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
+ *
+ * @file        error-description.cpp
+ * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version     1.0
+ * @brief       Implementatin of errorToString function.
+ */
+
+#include <string.h>
+
+#include "error-description.h"
+#include "symbol-visibility.h"
+
+#define MAX_BUF 256
+
+COMMON_API
+std::string errnoToString(int err)
+{
+       char buffer[MAX_BUF] = {};
+#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE
+
+       if (0 == strerror_r(err, buffer, MAX_BUF))
+               return std::string(buffer);
+
+#else
+       char *result = strerror_r(err, buffer, MAX_BUF);
+
+       if (result)
+               return std::string(result);
+
+#endif
+       return std::string();
+}
diff --git a/src/util/error-description.h b/src/util/error-description.h
new file mode 100644 (file)
index 0000000..c189d21
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2000 - 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
+ *
+ * @file        error-description.h
+ * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version     1.0
+ * @brief       Implementatin of errorToString function.
+ */
+#ifndef _AUTH_PASSWD_ERROR_DESCRIPTION_
+#define _AUTH_PASSWD_ERROR_DESCRIPTION_
+
+#include <string>
+#include <cerrno>
+
+std::string errnoToString(int err = errno);
+
+#endif // _AUTH_PASSWD_ERROR_DESCRIPTION_
diff --git a/src/util/exception.h b/src/util/exception.h
new file mode 100644 (file)
index 0000000..92d419d
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+/*
+ * @file    exception.h
+ * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ * @brief   Header file for base exception
+ */
+
+#ifndef AUTH_PASSWD_EXCEPTION_H
+#define AUTH_PASSWD_EXCEPTION_H
+
+#include <string>
+#include <cstring>
+#include <cstdio>
+#include <exception>
+#include <cstdlib>
+#include <sstream>
+#include "symbol-visibility.h"
+
+
+void LogUnhandledException(const std::string &str);
+void LogUnhandledException(const std::string &str,
+                                               const char *filename,
+                                               int line,
+                                               const char *function);
+
+class COMMON_API Exception {
+       private:
+               static unsigned int m_exceptionCount;
+               static Exception *m_lastException;
+               static void (*m_terminateHandler)();
+
+               static void AddRef(Exception *exception) {
+                       if (!m_exceptionCount)
+                               m_terminateHandler = std::set_terminate(&TerminateHandler);
+
+                       ++m_exceptionCount;
+                       m_lastException = exception;
+               }
+
+               static void UnRef(Exception *e) {
+                       if (m_lastException == e)
+                               m_lastException = NULL;
+
+                       --m_exceptionCount;
+
+                       if (!m_exceptionCount) {
+                               std::set_terminate(m_terminateHandler);
+                               m_terminateHandler = NULL;
+                       }
+               }
+
+               static void TerminateHandler() {
+                       if (m_lastException != NULL) {
+                               DisplayKnownException(*m_lastException);
+                               abort();
+                       } else {
+                               DisplayUnknownException();
+                               abort();
+                       }
+               }
+
+               Exception *m_reason;
+               std::string m_path;
+               std::string m_function;
+               int m_line;
+
+       protected:
+               std::string m_message;
+               std::string m_className;
+
+       public:
+               static std::string KnownExceptionToString(const Exception &e) {
+                       std::ostringstream message;
+                       message <<
+                                       "\033[1;5;31m\n=== Unhandled Exception occurred ===\033[m\n\n";
+                       message << "\033[1;33mException trace:\033[m\n\n";
+                       message << e.DumpToString();
+                       message << "\033[1;31m\n=== Will now abort ===\033[m\n";
+                       return message.str();
+               }
+
+               static std::string UnknownExceptionToString() {
+                       std::ostringstream message;
+                       message <<
+                                       "\033[1;5;31m\n=== Unhandled Non-exception occurred ===\033[m\n\n";
+                       message << "\033[1;31m\n=== Will now abort ===\033[m\n";
+                       return message.str();
+               }
+
+               static void DisplayKnownException(const Exception &e) {
+                       LogUnhandledException(KnownExceptionToString(e).c_str());
+               }
+
+               static void DisplayUnknownException() {
+                       LogUnhandledException(UnknownExceptionToString().c_str());
+               }
+
+               Exception(const Exception &other) {
+                       // Deep copy
+                       if (other.m_reason != NULL)
+                               m_reason = new Exception(*other.m_reason);
+                       else
+                               m_reason = NULL;
+
+                       m_message = other.m_message;
+                       m_path = other.m_path;
+                       m_function = other.m_function;
+                       m_line = other.m_line;
+                       m_className = other.m_className;
+                       AddRef(this);
+               }
+
+               Exception &operator =(const Exception &other) {
+                       if (this == &other)
+                               return *this;
+
+                       // Deep copy
+                       if (other.m_reason != NULL)
+                               m_reason = new Exception(*other.m_reason);
+                       else
+                               m_reason = NULL;
+
+                       m_message = other.m_message;
+                       m_path = other.m_path;
+                       m_function = other.m_function;
+                       m_line = other.m_line;
+                       m_className = other.m_className;
+                       AddRef(this);
+                       return *this;
+               }
+
+               Exception(const char *path,
+                               const char *function,
+                               int line,
+                               const std::string &message) :
+                       m_reason(NULL),
+                       m_path(path),
+                       m_function(function),
+                       m_line(line),
+                       m_message(message) {
+                       AddRef(this);
+               }
+
+               Exception(const char *path,
+                               const char *function,
+                               int line,
+                               const Exception &reason,
+                               const std::string &message) :
+                       m_reason(new Exception(reason)),
+                       m_path(path),
+                       m_function(function),
+                       m_line(line),
+                       m_message(message) {
+                       AddRef(this);
+               }
+
+               virtual ~Exception() throw() {
+                       if (m_reason != NULL) {
+                               delete m_reason;
+                               m_reason = NULL;
+                       }
+
+                       UnRef(this);
+               }
+
+               void Dump() const {
+                       // Show reason first
+                       if (m_reason != NULL)
+                               m_reason->Dump();
+
+                       // Afterward, dump exception
+                       const char *file = strchr(m_path.c_str(), '/');
+
+                       if (file == NULL)
+                               file = m_path.c_str();
+                       else
+                               ++file;
+
+                       printf("\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n",
+                               file, m_line,
+                               m_function.c_str(),
+                               m_className.c_str(),
+                               m_message.empty() ? "<EMPTY>" : m_message.c_str());
+               }
+
+               std::string DumpToString() const {
+                       std::string ret;
+
+                       if (m_reason != NULL)
+                               ret = m_reason->DumpToString();
+
+                       const char *file = strchr(m_path.c_str(), '/');
+
+                       if (file == NULL)
+                               file = m_path.c_str();
+                       else
+                               ++file;
+
+                       char buf[1024];
+                       snprintf(buf,
+                                       sizeof(buf),
+                                       "\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n",
+                                       file,
+                                       m_line,
+                                       m_function.c_str(),
+                                       m_className.c_str(),
+                                       m_message.empty() ? "<EMPTY>" : m_message.c_str());
+                       buf[sizeof(buf) - 1] = '\n';
+                       ret += buf;
+                       return ret;
+               }
+
+               Exception *GetReason() const {
+                       return m_reason;
+               }
+
+               std::string GetPath() const {
+                       return m_path;
+               }
+
+               std::string GetFunction() const {
+                       return m_function;
+               }
+
+               int GetLine() const {
+                       return m_line;
+               }
+
+               std::string GetMessage() const {
+                       return m_message;
+               }
+
+               std::string GetClassName() const {
+                       return m_className;
+               }
+};
+
+
+#define Try try
+
+#define Throw(ClassName) \
+       throw ClassName(__FILE__, __FUNCTION__, __LINE__)
+
+#define ThrowMsg(ClassName, Message)                                               \
+       do {                                                                           \
+               std::ostringstream dplLoggingStream;                                       \
+               dplLoggingStream << Message;                                               \
+               throw ClassName(__FILE__, __FUNCTION__, __LINE__, dplLoggingStream.str()); \
+       } while (0)
+
+#define ReThrow(ClassName) \
+       throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception)
+
+#define ReThrowMsg(ClassName, Message)   \
+       throw ClassName(__FILE__,            \
+                                       __FUNCTION__,        \
+                                       __LINE__,            \
+                                       _rethrown_exception, \
+                                       Message)
+
+#define Catch(ClassName) \
+       catch (const ClassName &_rethrown_exception)
+
+#define DECLARE_EXCEPTION_TYPE(BaseClass, Class)               \
+       class Class : public BaseClass {                           \
+       public:                                                    \
+               Class(const char *path,                                \
+                               const char *function,                          \
+                               int line,                                      \
+                               const std::string & message = std::string()) : \
+                       BaseClass(path, function, line, message) {         \
+                       BaseClass::m_className = #Class;                   \
+               }                                                      \
+               Class(const char *path,                                \
+                         const char *function,                            \
+                         int line,                                        \
+                         const Exception & reason,            \
+                         const std::string & message = std::string()) :   \
+                       BaseClass(path, function, line, reason, message) { \
+                       BaseClass::m_className = #Class;                   \
+               }                                                      \
+       };
+
+#define UNHANDLED_EXCEPTION_HANDLER_BEGIN try
+
+#define UNHANDLED_EXCEPTION_HANDLER_END                                                 \
+       catch (const Exception &exception) {                                    \
+               std::ostringstream msg;                                                         \
+               msg << Exception::KnownExceptionToString(exception);                \
+               LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \
+               abort();                                                                        \
+       } catch (std::exception& e) {                                                       \
+               std::ostringstream msg;                                                         \
+               msg << e.what();                                                                \
+               msg << "\n";                                                                    \
+               msg << Exception::UnknownExceptionToString();                       \
+               LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \
+               abort();                                                                        \
+       } catch (...) {                                                                     \
+               std::ostringstream msg;                                                         \
+               msg << Exception::UnknownExceptionToString();                       \
+               LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \
+               abort();                                                                        \
+       }
+
+/**
+ * Internal exception definitions
+ *
+ * These should normally not happen.
+ * Usually, exception trace with internal error includes
+ * important messages.
+ */
+DECLARE_EXCEPTION_TYPE(Exception, InternalError) ///< Unexpected error from
+// underlying libraries or
+// kernel
+
+
+#endif // AUTH_PASSWD_EXCEPTION_H
diff --git a/src/util/fstream_accessors.h b/src/util/fstream_accessors.h
new file mode 100644 (file)
index 0000000..7ee4c52
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) 2000 - 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
+ *
+ * @file        fstream-helper.h
+ * @author      Marek Smolinski (m.smolinski@samsung.com)
+ * @version     1.0
+ * @brief       This file is the implementation file of fstream-helper
+ *
+ */
+
+#ifndef AUTH_PASSWD_FSTREAM_ACCESSORS_H
+#define AUTH_PASSWD_FSTREAM_ACCESSORS_H
+
+/*
+ * Bypass lack of public member function to get file
+ * descriptor from fstream objects in std
+ * This feature is needed for flushing data from kernel space buffer to
+ * physical device [fsync(int fd) - syscall] on opened fstream object
+*/
+       template<typename T>
+       class FstreamAccessors : T::__filebuf_type {
+               typedef FstreamAccessors<T> MyType;
+       public:
+               static int GetFd(T &strm)
+               {
+                       return static_cast<MyType *>(strm.rdbuf())->_M_file.fd();
+               }
+       };
+
+#endif // AUTH_PASSWD_FSTREAM_ACCESSORS_H
diff --git a/src/util/ipassword-file.h b/src/util/ipassword-file.h
new file mode 100644 (file)
index 0000000..3a1d26c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  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
+ */
+#ifndef _IPASSWORD_FILE_H_
+#define _IPASSWORD_FILE_H_
+
+#include <string>
+#include <time.h>
+#include <hal/hal-security-auth-error.h>
+
+#include "ipassword.h"
+
+struct IPasswordFile {
+       IPasswordFile() = default;
+       virtual ~IPasswordFile() = default;
+
+       IPasswordFile(const IPasswordFile&) = delete;
+       IPasswordFile& operator=(const IPasswordFile&) = delete;
+
+       IPasswordFile(IPasswordFile&&) = delete;
+       IPasswordFile& operator=(IPasswordFile&&) = delete;
+
+       virtual int write_memory_to_file(uid_t user_id) const = 0;
+       virtual int write_attempt_to_file(uid_t user_id) const = 0;
+
+       virtual int set_password(uid_t user_id, const char* password) = 0;
+       virtual int check_password(uid_t user_id, const char* password) = 0;
+
+       virtual int is_password_active(uid_t user_id) const = 0;
+
+       virtual int get_password_type(uid_t user_id, hal_security_auth_password_type_e *password_type) const = 0;
+       virtual int set_max_history_size(uid_t user_id, unsigned int history_size) = 0;
+
+       virtual int get_max_history_size(uid_t user_id, unsigned int *history_size) const = 0;
+
+       virtual int get_expire_time(uid_t user_id, unsigned int *expire_time) const = 0;
+       virtual int set_expire_time(uid_t user_id, unsigned int expire_time) = 0;
+
+       virtual int get_expire_time_left(uid_t user_id, unsigned int *expire_time_left) const = 0;
+       virtual int set_expire_time_left(uid_t user_id, unsigned int expire_time_left) = 0;
+
+       virtual int get_attempt(uid_t user_id, unsigned int *attempt) const = 0;
+       virtual int reset_attempt(uid_t user_id) = 0;
+       virtual int increment_attempt(uid_t user_id) = 0;
+       virtual int get_max_attempt(uid_t user_id, unsigned int *max_attempt) const = 0;
+       virtual int set_max_attempt(uid_t user_id, unsigned int max_attempt) = 0;
+
+       virtual int is_password_reused(uid_t user_id, const char* password) const = 0;
+
+       virtual int check_expiration(uid_t user_id) const = 0;
+       virtual int check_attempt_exceeded(uid_t user_id) const = 0;
+       virtual int is_ignore_period(uid_t user_id) const = 0;
+
+       virtual int is_history_active(uid_t user_id) const = 0;
+       virtual uid_t get_user_id() const = 0;
+};
+
+using PasswordFileFactory = IPasswordFile* (*)(unsigned int);
+#endif
diff --git a/src/util/ipassword.cpp b/src/util/ipassword.cpp
new file mode 100644 (file)
index 0000000..68e4d8d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  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
+ */
+#include <openssl/sha.h>
+
+#include "ipassword.h"
+#include "log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+NoPassword::NoPassword(IStream&)
+{
+}
+
+void NoPassword::Serialize(IStream &stream) const
+{
+       Serialization::Serialize(stream, static_cast<unsigned int>(PasswordType::NONE));
+}
+
+bool NoPassword::match(const std::string &pass) const
+{
+       return pass.empty();
+}
+
+SHA256Password::SHA256Password(IStream &stream)
+{
+       Deserialization::Deserialize(stream, m_hash);
+}
+
+SHA256Password::SHA256Password(const std::string &password) : m_hash(hash(password))
+{
+}
+
+SHA256Password::SHA256Password(const RawHash &paramHash) : m_hash(paramHash)
+{
+}
+
+void SHA256Password::Serialize(IStream &stream) const
+{
+       Serialization::Serialize(stream, static_cast<unsigned int>(PasswordType::SHA256));
+       Serialization::Serialize(stream, m_hash);
+}
+
+bool SHA256Password::match(const std::string &password) const
+{
+       return m_hash == hash(password);
+}
+
+RawHash SHA256Password::hash(const std::string &password)
+{
+       RawHash result(SHA256_DIGEST_LENGTH);
+       SHA256_CTX context;
+       SHA256_Init(&context);
+       SHA256_Update(&context, reinterpret_cast<const unsigned char *>(password.c_str()),
+                               password.size());
+       SHA256_Final(result.data(), &context);
+       return result;
+}
+#ifdef __cplusplus
+}
+#endif
+
+template <>
+void Deserialization::Deserialize(IStream &stream, IPasswordPtr &ptr)
+{
+       unsigned int algorithm;
+       Deserialization::Deserialize(stream, algorithm);
+
+       switch (algorithm) {
+       case (unsigned int)IPassword::PasswordType::NONE:
+               ptr.reset(new NoPassword());
+               break;
+
+       case (unsigned int)IPassword::PasswordType::SHA256:
+               ptr.reset(new SHA256Password(stream));
+               break;
+
+       default:
+               LOGE("FStreamReadError");
+       }
+}
\ No newline at end of file
diff --git a/src/util/ipassword.h b/src/util/ipassword.h
new file mode 100644 (file)
index 0000000..3563a39
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  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
+ */
+#ifndef _IPASSWORD_H_
+#define _IPASSWORD_H_
+
+#include <string>
+#include <memory>
+#include <limits>
+#include <time.h>
+
+#include "serialization.h"
+
+constexpr time_t PASSWORD_INFINITE_EXPIRATION_TIME = std::numeric_limits<time_t>::max();
+
+struct IPassword;
+using RawHash = std::vector<unsigned char>;
+using IPasswordPtr = std::shared_ptr<IPassword>;
+using PasswordList = std::list<IPasswordPtr>;
+
+struct IPassword: public ISerializable {
+
+       enum class PasswordType : unsigned int {
+               NONE = 0,
+               SHA256 = 1,
+       };
+
+       virtual bool match(const std::string &password) const = 0;
+};
+
+class NoPassword: public IPassword {
+public:
+       NoPassword() = default;
+       NoPassword(IStream &);
+
+       void Serialize(IStream &stream) const;
+       bool match(const std::string &pass) const;
+};
+
+class SHA256Password: public IPassword {
+public:
+       SHA256Password(IStream &stream);
+       SHA256Password(const std::string &password);
+       SHA256Password(const RawHash &paramHash);
+
+       void Serialize(IStream &stream) const;
+       bool match(const std::string &password) const;
+
+private:
+       static RawHash hash(const std::string &password);
+
+       RawHash m_hash;
+};
+
+template <>
+void Deserialization::Deserialize(IStream &stream, IPasswordPtr &ptr);
+
+#endif
diff --git a/src/util/log.cpp b/src/util/log.cpp
new file mode 100644 (file)
index 0000000..fb2a4ce
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************
+ *
+ * Copyright 2025 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+#include <dlog.h>
+#include <syslog.h>
+
+#ifdef NDEBUG
+int __log_level = LOG_ERR;
+#else
+int __log_level = LOG_DEBUG;
+#endif
+
+#define SECURITY_AUTH_LOG_TAG "SECURITY_AUTH_BACKEND"
+
+void security_auth_print(int priority, char const *fmt, ...)
+{
+       log_priority dlog_prio;
+
+       switch (priority) {
+               case LOG_EMERG:
+                       dlog_prio = DLOG_FATAL;
+                       break;
+               case LOG_ERR:
+                       dlog_prio = DLOG_ERROR;
+                       break;
+               case LOG_WARNING:
+                       dlog_prio = DLOG_WARN;
+                       break;
+               case LOG_INFO:
+                       dlog_prio = DLOG_INFO;
+                       break;
+               case LOG_DEBUG:
+                       dlog_prio = DLOG_DEBUG;
+                       break;
+               default:
+                       dlog_prio = DLOG_DEFAULT;
+       }
+
+       va_list ap;
+       va_start(ap, fmt);
+       (void) dlog_vprint(dlog_prio, SECURITY_AUTH_LOG_TAG, fmt, ap);
+       va_end(ap);
+}
diff --git a/src/util/log.h b/src/util/log.h
new file mode 100644 (file)
index 0000000..e5e09e8
--- /dev/null
@@ -0,0 +1,70 @@
+/******************************************************************
+ *
+ * Copyright 2025 Samsung Electronics 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.
+ *
+ ******************************************************************/
+#ifndef SHARED_LOG_H_
+#define SHARED_LOG_H_
+
+#include <stdlib.h>
+#include <syslog.h>
+#include <sstream>
+
+#define UNUSED __attribute__((unused))
+
+extern int __log_level;
+extern void security_auth_print(int priority, char const *fmt, ...);
+
+namespace {
+       template <typename ...Args>
+       void UNUSED __LOG_FUN(int level, const std::stringstream &format, Args&&... args) {
+               security_auth_print(level, format.str().c_str(), std::forward<Args>(args)...);
+       }
+
+       template <>
+       void UNUSED __LOG_FUN(int level, const std::stringstream &format) {
+               security_auth_print(level, "%s", format.str().c_str());
+       }
+
+       template <typename ...Args>
+       void UNUSED __LOG_FUN(int level, const char *format, Args&&... args) {
+               security_auth_print(level, format, std::forward<Args>(args)...);
+       }
+
+       template <>
+       void UNUSED __LOG_FUN(int level, const char *format) {
+               security_auth_print(level, "%s", format);
+       }
+
+} // namespace anonymous
+
+#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)
+
+#define __LOG(LEVEL, FORMAT, ...) \
+       do { \
+               if (LEVEL <= __log_level) { \
+                       std::stringstream __LOG_FORMAT; \
+                       __LOG_FORMAT << __FILENAME__ << ": " << __func__ << "(" << __LINE__ << ") > " << FORMAT; \
+                       __LOG_FUN(LEVEL, __LOG_FORMAT, ##__VA_ARGS__); \
+               } \
+       } while (0)
+
+#define LOGM(...)  __LOG(LOG_EMERG, __VA_ARGS__)   /* system is unusable */
+#define LOGE(...)  __LOG(LOG_ERR, __VA_ARGS__)     /* error conditions */
+#define LOGW(...)  __LOG(LOG_WARNING, __VA_ARGS__) /* warning conditions */
+#define LOGI(...)  __LOG(LOG_INFO, __VA_ARGS__)    /* informational */
+#define LOGD(...)  __LOG(LOG_DEBUG, __VA_ARGS__)   /* debug-level messages */
+
+#endif /* SHARED_LOG_H_ */
diff --git a/src/util/password-file-buffer.cpp b/src/util/password-file-buffer.cpp
new file mode 100644 (file)
index 0000000..787dbe0
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2000 - 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
+ */
+/*
+ * @file        password-file-buffer.cpp
+ * @author      Lukasz Kostyra (l.kostyra@partner.samsung.com)
+ * @version     1.0
+ * @brief       Implementation of PasswordFileBuffer, used for serialization in PasswordFile class
+ */
+
+
+#include <fstream>
+#include <iterator>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fstream_accessors.h"
+#include "password-file-buffer.h"
+#include "log.h"
+
+PasswordFileBuffer::PasswordFileBuffer(): m_bufferReadBytes(0) {}
+
+void PasswordFileBuffer::Read(size_t num, void *bytes)
+{
+       if (m_buffer.empty())
+               LOGE("Buffer doesn't contain any data.");
+
+       if ((m_bufferReadBytes + num) > m_buffer.size())
+               LOGE("Not enough buffer to read " << num << " data.");
+
+       void *ret = memcpy(bytes, &m_buffer[m_bufferReadBytes], num);
+
+       if (ret == 0)
+               LOGE("Failed to read " << num << " bytes.");
+
+       m_bufferReadBytes += num;
+}
+
+void PasswordFileBuffer::Write(size_t num, const void *bytes)
+{
+       const char *buffer = static_cast<const char *>(bytes);
+       std::copy(buffer, buffer + num, std::back_inserter(m_buffer));
+}
+
+void PasswordFileBuffer::Save(const std::string &path)
+{
+       std::ofstream file(path, std::ofstream::trunc);
+
+       if (!file.good())
+               LOGE("Error while opening file stream. file=" << path);
+
+       file.write(m_buffer.data(), m_buffer.size());
+
+       if (!file)
+               LOGE("Failed to write data. file=" << path);
+
+       file.flush();
+       if (::fsync(FstreamAccessors<std::ofstream>::GetFd(file)) != 0)
+               LOGE("Failed to synchronize a file's state. file=" << path);
+       file.close();
+}
+
+void PasswordFileBuffer::Load(const std::string &path)
+{
+       std::ifstream file(path, std::ifstream::binary);
+
+       if (!file.good())
+               LOGE("Error while opening file stream. file=" << path);
+
+       //reset read bytes counter
+       m_bufferReadBytes = 0;
+       m_buffer.assign(std::istreambuf_iterator<char>(file),
+                                       std::istreambuf_iterator<char>());
+
+       if (!file)
+               LOGE("Failed to read data. Failbit: " << file.fail() << ", Badbit: " << file.bad() << ", file=" << path);
+}
\ No newline at end of file
diff --git a/src/util/password-file-buffer.h b/src/util/password-file-buffer.h
new file mode 100644 (file)
index 0000000..5b079a6
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2000 - 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
+ */
+/*
+ * @file        password-file-buffer.h
+ * @author      Zbigniew Jasinski (z.jasinski@samsung.com)
+ * @author      Lukasz Kostyra (l.kostyra@partner.samsung.com)
+ * @version     1.0
+ * @brief       Implementation of password file buffer, used for serialization in password-manager.h
+ */
+
+#ifndef _PASSWORD_FILE_BUFFER_H_
+#define _PASSWORD_FILE_BUFFER_H_
+
+#include <stddef.h>
+#include <vector>
+#include <string>
+
+#include "serialization.h"
+
+class PasswordFileBuffer: public IStream {
+       public:
+               PasswordFileBuffer();
+
+               virtual void Read(size_t num, void *bytes);
+               virtual void Write(size_t num, const void *bytes);
+
+               void Save(const std::string &path);
+               void Load(const std::string &path);
+
+       private:
+               typedef std::vector<char> DataBuffer;
+
+               DataBuffer m_buffer;
+               size_t m_bufferReadBytes;
+};
+
+#endif
diff --git a/src/util/serialization.h b/src/util/serialization.h
new file mode 100644 (file)
index 0000000..632fdfa
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2011 - 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.
+ */
+/**
+ * @file    serialization.h
+ * @author  Tomasz Swierczek (t.swierczek@samsung.com)
+ * @version 1.0
+ * @brief   Interfaces and templates used for data serialization.
+ */
+#ifndef SERIALIZATION_H
+#define SERIALIZATION_H
+
+#include <string>
+#include <vector>
+#include <set>
+#include <list>
+#include <map>
+#include <memory>
+
+#include "log.h"
+
+// Abstract data stream buffer
+class IStream {
+       public:
+               virtual void Read(size_t num, void *bytes) = 0;
+               virtual void Write(size_t num, const void *bytes) = 0;
+               virtual ~IStream() {}
+};
+
+// Serializable interface
+class ISerializable {
+       public:
+               ISerializable() {}
+               ISerializable(IStream &) {}
+               virtual void Serialize(IStream &) const = 0;
+               virtual ~ISerializable() {}
+};
+
+struct Serialization {
+       // serialization
+       // normal functions
+
+       // ISerializable objects
+       static void Serialize(IStream &stream, const ISerializable &object) {
+               object.Serialize(stream);
+       }
+       static void Serialize(IStream &stream, const ISerializable *const object) {
+               object->Serialize(stream);
+       }
+
+       // char
+       static void Serialize(IStream &stream, const char value) {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream &stream, const char *const value) {
+               stream.Write(sizeof(*value), value);
+       }
+
+       // unsigned char
+       static void Serialize(IStream &stream, const unsigned char value) {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream &stream, const unsigned char *const value) {
+               stream.Write(sizeof(*value), value);
+       }
+
+       // unsigned int
+       static void Serialize(IStream &stream, const unsigned value) {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream &stream, const unsigned *const value) {
+               stream.Write(sizeof(*value), value);
+       }
+
+       // int
+       static void Serialize(IStream &stream, const int value) {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream &stream, const int *const value) {
+               stream.Write(sizeof(*value), value);
+       }
+
+       // bool
+       static void Serialize(IStream &stream, const bool value) {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream &stream, const bool *const value) {
+               stream.Write(sizeof(*value), value);
+       }
+
+       // time_t
+       static void Serialize(IStream &stream, const time_t value) {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream &stream, const time_t *const value) {
+               stream.Write(sizeof(*value), value);
+       }
+
+       // std::string
+       static void Serialize(IStream &stream, const std::string &str) {
+               int length = str.size();
+               stream.Write(sizeof(length), &length);
+               stream.Write(length, str.c_str());
+       }
+       static void Serialize(IStream &stream, const std::string *const str) {
+               int length = str->size();
+               stream.Write(sizeof(length), &length);
+               stream.Write(length, str->c_str());
+       }
+
+       // STL templates
+
+       // std::list
+       template <typename T>
+       static void Serialize(IStream &stream, const std::list<T> &list) {
+               int length = list.size();
+               stream.Write(sizeof(length), &length);
+
+               for (typename std::list<T>::const_iterator list_iter = list.begin();
+                               list_iter != list.end(); list_iter++)
+                       Serialize(stream, *list_iter);
+       }
+       template <typename T>
+       static void Serialize(IStream &stream, const std::list<T> *const list) {
+               Serialize(stream, *list);
+       }
+
+       // std::vector
+       template <typename T>
+       static void Serialize(IStream &stream, const std::vector<T> &vec) {
+               int length = vec.size();
+               stream.Write(sizeof(length), &length);
+
+               for (typename std::vector<T>::const_iterator vec_iter = vec.begin();
+                               vec_iter != vec.end(); vec_iter++)
+                       Serialize(stream, *vec_iter);
+       }
+       template <typename T>
+       static void Serialize(IStream &stream, const std::vector<T> *const vec) {
+               Serialize(stream, *vec);
+       }
+
+       // std::set
+       template <typename T>
+       static void Serialize(IStream &stream, const std::set<T> &set) {
+               size_t length = set.size();
+               stream.Write(sizeof(length), &length);
+
+               for (const auto &item : set)
+                       Serialize(stream, item);
+       }
+
+       // std::pair
+       template <typename A, typename B>
+       static void Serialize(IStream &stream, const std::pair<A, B> &p) {
+               Serialize(stream, p.first);
+               Serialize(stream, p.second);
+       }
+       template <typename A, typename B>
+       static void Serialize(IStream &stream, const std::pair<A, B> *const p) {
+               Serialize(stream, *p);
+       }
+
+       // std::map
+       template <typename K, typename T>
+       static void Serialize(IStream &stream, const std::map<K, T> &map) {
+               int length = map.size();
+               stream.Write(sizeof(length), &length);
+               typename std::map<K, T>::const_iterator it;
+
+               for (it = map.begin(); it != map.end(); ++it) {
+                       Serialize(stream, (*it).first);
+                       Serialize(stream, (*it).second);
+               }
+       }
+       template <typename K, typename T>
+       static void Serialize(IStream &stream, const std::map<K, T> *const map) {
+               Serialize(stream, *map);
+       }
+
+       // std::unique_ptr
+       template <typename T>
+       static void Serialize(IStream &stream, const std::unique_ptr<T> &p) {
+               Serialize(stream, *p);
+       }
+
+       // std::shared_ptr
+       template <typename T>
+       static void Serialize(IStream &stream, const std::shared_ptr<T> &p) {
+               Serialize(stream, *p);
+       }
+}; // struct Serialization
+
+struct Deserialization {
+       // deserialization
+       // normal functions
+
+       // ISerializable objects
+       // T instead of ISerializable is needed to call proper constructor
+       template <typename T>
+       static void Deserialize(IStream &stream, T &object) {
+               object = T(stream);
+       }
+       template <typename T>
+       static void Deserialize(IStream &stream, T *&object) {
+               object = new T(stream);
+       }
+
+       // char
+       static void Deserialize(IStream &stream, char &value) {
+               stream.Read(sizeof(value), &value);
+       }
+       static void Deserialize(IStream &stream, char *&value) {
+               value = new char;
+               std::unique_ptr<char> ptr(value);
+               stream.Read(sizeof(*value), value);
+               ptr.release();
+       }
+
+       // unsigned char
+       static void Deserialize(IStream &stream, unsigned char &value) {
+               stream.Read(sizeof(value), &value);
+       }
+       static void Deserialize(IStream &stream, unsigned char *&value) {
+               value = new unsigned char;
+               std::unique_ptr<unsigned char> ptr(value);
+               stream.Read(sizeof(*value), value);
+               ptr.release();
+       }
+
+       // unsigned int
+       static void Deserialize(IStream &stream, unsigned &value) {
+               stream.Read(sizeof(value), &value);
+       }
+       static void Deserialize(IStream &stream, unsigned *&value) {
+               value = new unsigned;
+               std::unique_ptr<unsigned> ptr(value);
+               stream.Read(sizeof(*value), value);
+               ptr.release();
+       }
+
+       // int
+       static void Deserialize(IStream &stream, int &value) {
+               stream.Read(sizeof(value), &value);
+       }
+       static void Deserialize(IStream &stream, int *&value) {
+               value = new int;
+               std::unique_ptr<int> ptr(value);
+               stream.Read(sizeof(*value), value);
+               ptr.release();
+       }
+
+       // bool
+       static void Deserialize(IStream &stream, bool &value) {
+               stream.Read(sizeof(value), &value);
+       }
+       static void Deserialize(IStream &stream, bool *&value) {
+               value = new bool;
+               std::unique_ptr<bool> ptr(value);
+               stream.Read(sizeof(*value), value);
+               ptr.release();
+       }
+
+       // time_t
+       static void Deserialize(IStream &stream, time_t &value) {
+               stream.Read(sizeof(value), &value);
+       }
+       static void Deserialize(IStream &stream, time_t *&value) {
+               value = new time_t;
+               std::unique_ptr<time_t> ptr(value);
+               stream.Read(sizeof(*value), value);
+               ptr.release();
+       }
+
+       // std::string
+       static void Deserialize(IStream &stream, std::string &str) {
+               int length;
+               stream.Read(sizeof(length), &length);
+               if (length < 0)
+                       LOGE("Invalid length of std::string (less than 0)");
+
+               char * buf = new char[length + 1];
+               std::unique_ptr<char[]> ptr(buf);
+               stream.Read(length, buf);
+               buf[length] = 0;
+               str = std::string(buf);
+       }
+       static void Deserialize(IStream &stream, std::string *&str) {
+               int length;
+               stream.Read(sizeof(length), &length);
+               if (length < 0)
+                       LOGE("Invalid length of std::string (less than 0)");
+
+               char * buf = new char[length + 1];
+               std::unique_ptr<char[]> ptr(buf);
+               stream.Read(length, buf);
+               buf[length] = 0;
+               str = new std::string(buf);
+       }
+
+       // STL templates
+
+       // std::list
+       template <typename T>
+       static void Deserialize(IStream &stream, std::list<T> &list) {
+               int length;
+               stream.Read(sizeof(length), &length);
+               if (length < 0)
+                       LOGE("Invalid length of std::list (less than 0)");
+
+               for (int i = 0; i < length; ++i) {
+                       T obj;
+                       Deserialize(stream, obj);
+                       list.push_back(std::move(obj));
+               }
+       }
+       template <typename T>
+       static void Deserialize(IStream &stream, std::list<T> *&list) {
+               list = new std::list<T>;
+               std::unique_ptr<std::list<T>> ptr(list);
+               Deserialize(stream, *list);
+               ptr.release();
+       }
+
+       // std::vector
+       template <typename T>
+       static void Deserialize(IStream &stream, std::vector<T> &vec) {
+               int length;
+               stream.Read(sizeof(length), &length);
+               if (length < 0)
+                       LOGE("Invalid length of std::vector (less than 0)");
+
+               for (int i = 0; i < length; ++i) {
+                       T obj;
+                       Deserialize(stream, obj);
+                       vec.push_back(std::move(obj));
+               }
+       }
+       template <typename T>
+       static void Deserialize(IStream &stream, std::vector<T> *&vec) {
+               vec = new std::vector<T>;
+               std::unique_ptr<std::vector<T>> ptr(vec);
+               Deserialize(stream, *vec);
+               ptr.release();
+       }
+
+       // std::set
+       template <typename T>
+       static void Deserialize(IStream &stream, std::set<T> &set) {
+               size_t length;
+               stream.Read(sizeof(length), &length);
+               for (size_t i = 0; i < length; ++i) {
+                       T obj;
+                       Deserialize(stream, obj);
+                       set.insert(std::move(obj));
+               }
+       }
+
+       // std::pair
+       template <typename A, typename B>
+       static void Deserialize(IStream &stream, std::pair<A, B> &p) {
+               Deserialize(stream, p.first);
+               Deserialize(stream, p.second);
+       }
+       template <typename A, typename B>
+       static void Deserialize(IStream &stream, std::pair<A, B> *&p) {
+               p = new std::pair<A, B>;
+               std::unique_ptr<std::pair<A, B>> ptr(p);
+               Deserialize(stream, *p);
+               ptr.release();
+       }
+
+       // std::tuple
+       template <std::size_t I = 0, typename... Tp>
+       static inline typename std::enable_if<I == sizeof...(Tp), void>::type
+       Deserialize(IStream&, std::tuple<Tp...>&)
+       {}
+
+       template <std::size_t I = 0, typename... Tp>
+       static inline typename std::enable_if<I < sizeof...(Tp), void>::type
+       Deserialize(IStream& stream, std::tuple<Tp...>& t) {
+               Deserialize(stream, std::get<I>(t));
+               Deserialize<I+1>(stream, t);
+       }
+
+       template <typename... Tp>
+       static void Deserialize(IStream &stream, std::tuple<Tp...> *&t) {
+               t = new std::tuple<Tp...>;
+               std::unique_ptr<std::tuple<Tp...>> ptr(t);
+               Deserialize(stream, *t);
+               ptr.release();
+       }
+
+       // std::map
+       template <typename K, typename T>
+       static void Deserialize(IStream &stream, std::map<K, T> &map) {
+               int length;
+               stream.Read(sizeof(length), &length);
+               if (length < 0)
+                       LOGE("Invalid size of std::map (less than 0)");
+
+               for (int i = 0; i < length; ++i) {
+                       K key;
+                       T obj;
+                       Deserialize(stream, key);
+                       Deserialize(stream, obj);
+                       map[key] = std::move(obj);
+               }
+       }
+       template <typename K, typename T>
+       static void Deserialize(IStream &stream, std::map<K, T> *&map) {
+               map = new std::map<K, T>;
+               std::unique_ptr<std::map<K, T>> ptr(map);
+               Deserialize(stream, *map);
+               ptr.release();
+       }
+
+       template<typename T1, typename T2, typename... Tail>
+       static void Deserialize(IStream &stream, T1 &first, T2 &second, Tail&... tail) {
+               Deserialization::Deserialize(stream, first);
+               Deserialization::Deserialize(stream, second, tail...);
+       }
+}; // struct Deserialization
+
+#endif // SERIALIZATION_H
diff --git a/src/util/symbol-visibility.h b/src/util/symbol-visibility.h
new file mode 100644 (file)
index 0000000..1bdc485
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ *  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
+ *
+ *
+ * @file        symbol-visibility.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       define symbol visiblity for common library.
+ */
+
+#define COMMON_API __attribute__((visibility("default")))