From: Dongik Lee Date: Wed, 19 Mar 2025 07:54:35 +0000 (+0900) Subject: Add security auth backend implementation X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=59a2f34329f46c21f338084d4348dadac63114ba;p=platform%2Fhal%2Fbackend%2Femulator%2Fsecurity-auth.git Add security auth backend implementation Change-Id: Id1796f29d50bdd8f0996ef2843d620f7b980fb83 --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b149759 --- /dev/null +++ b/CMakeLists.txt @@ -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 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 index 0000000..a76fdba --- /dev/null +++ b/packaging/hal-backend-security-auth.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/hal-backend-security-auth.spec b/packaging/hal-backend-security-auth.spec new file mode 100644 index 0000000..0d206c0 --- /dev/null +++ b/packaging/hal-backend-security-auth.spec @@ -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 index 0000000..5c7d063 --- /dev/null +++ b/src/CMakeLists.txt @@ -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 index 0000000..22fbf17 --- /dev/null +++ b/src/hal_backend_security_auth.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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(&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(&m_attempt), sizeof(unsigned int)); + + if (!AttemptFile) { + LOGE(" Failed to write " << m_user << " attempt count."); + } + + AttemptFile.flush(); + if (::fsync(FstreamAccessors::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 : "<(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 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, ¤t_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 index 0000000..b92b97e --- /dev/null +++ b/src/hal_backend_security_auth.h @@ -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 +#include +#include +#include +#include +#include +#include + +#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 TimeDiff; + typedef std::chrono::time_point 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 index 0000000..254a59b --- /dev/null +++ b/src/hal_backend_security_auth_api.cpp @@ -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 + +#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 index 0000000..39b6392 --- /dev/null +++ b/src/util/error-description.cpp @@ -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 + +#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 index 0000000..c189d21 --- /dev/null +++ b/src/util/error-description.h @@ -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 +#include + +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 index 0000000..92d419d --- /dev/null +++ b/src/util/exception.h @@ -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 +#include +#include +#include +#include +#include +#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() ? "" : 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() ? "" : 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 index 0000000..7ee4c52 --- /dev/null +++ b/src/util/fstream_accessors.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000 - 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jooseong Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + * + * @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 + class FstreamAccessors : T::__filebuf_type { + typedef FstreamAccessors MyType; + public: + static int GetFd(T &strm) + { + return static_cast(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 index 0000000..3a1d26c --- /dev/null +++ b/src/util/ipassword-file.h @@ -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 +#include +#include + +#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 index 0000000..68e4d8d --- /dev/null +++ b/src/util/ipassword.cpp @@ -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 + +#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(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 ¶mHash) : m_hash(paramHash) +{ +} + +void SHA256Password::Serialize(IStream &stream) const +{ + Serialization::Serialize(stream, static_cast(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(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 index 0000000..3563a39 --- /dev/null +++ b/src/util/ipassword.h @@ -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 +#include +#include +#include + +#include "serialization.h" + +constexpr time_t PASSWORD_INFINITE_EXPIRATION_TIME = std::numeric_limits::max(); + +struct IPassword; +using RawHash = std::vector; +using IPasswordPtr = std::shared_ptr; +using PasswordList = std::list; + +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 ¶mHash); + + 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 index 0000000..fb2a4ce --- /dev/null +++ b/src/util/log.cpp @@ -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 +#include + +#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 index 0000000..e5e09e8 --- /dev/null +++ b/src/util/log.h @@ -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 +#include +#include + +#define UNUSED __attribute__((unused)) + +extern int __log_level; +extern void security_auth_print(int priority, char const *fmt, ...); + +namespace { + template + void UNUSED __LOG_FUN(int level, const std::stringstream &format, Args&&... args) { + security_auth_print(level, format.str().c_str(), std::forward(args)...); + } + + template <> + void UNUSED __LOG_FUN(int level, const std::stringstream &format) { + security_auth_print(level, "%s", format.str().c_str()); + } + + template + void UNUSED __LOG_FUN(int level, const char *format, Args&&... args) { + security_auth_print(level, format, std::forward(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 index 0000000..787dbe0 --- /dev/null +++ b/src/util/password-file-buffer.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000 - 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jooseong Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @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 +#include +#include +#include +#include + +#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(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::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(file), + std::istreambuf_iterator()); + + 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 index 0000000..5b079a6 --- /dev/null +++ b/src/util/password-file-buffer.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000 - 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jooseong Lee + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @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 +#include +#include + +#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 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 index 0000000..632fdfa --- /dev/null +++ b/src/util/serialization.h @@ -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 +#include +#include +#include +#include +#include + +#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 + static void Serialize(IStream &stream, const std::list &list) { + int length = list.size(); + stream.Write(sizeof(length), &length); + + for (typename std::list::const_iterator list_iter = list.begin(); + list_iter != list.end(); list_iter++) + Serialize(stream, *list_iter); + } + template + static void Serialize(IStream &stream, const std::list *const list) { + Serialize(stream, *list); + } + + // std::vector + template + static void Serialize(IStream &stream, const std::vector &vec) { + int length = vec.size(); + stream.Write(sizeof(length), &length); + + for (typename std::vector::const_iterator vec_iter = vec.begin(); + vec_iter != vec.end(); vec_iter++) + Serialize(stream, *vec_iter); + } + template + static void Serialize(IStream &stream, const std::vector *const vec) { + Serialize(stream, *vec); + } + + // std::set + template + static void Serialize(IStream &stream, const std::set &set) { + size_t length = set.size(); + stream.Write(sizeof(length), &length); + + for (const auto &item : set) + Serialize(stream, item); + } + + // std::pair + template + static void Serialize(IStream &stream, const std::pair &p) { + Serialize(stream, p.first); + Serialize(stream, p.second); + } + template + static void Serialize(IStream &stream, const std::pair *const p) { + Serialize(stream, *p); + } + + // std::map + template + static void Serialize(IStream &stream, const std::map &map) { + int length = map.size(); + stream.Write(sizeof(length), &length); + typename std::map::const_iterator it; + + for (it = map.begin(); it != map.end(); ++it) { + Serialize(stream, (*it).first); + Serialize(stream, (*it).second); + } + } + template + static void Serialize(IStream &stream, const std::map *const map) { + Serialize(stream, *map); + } + + // std::unique_ptr + template + static void Serialize(IStream &stream, const std::unique_ptr &p) { + Serialize(stream, *p); + } + + // std::shared_ptr + template + static void Serialize(IStream &stream, const std::shared_ptr &p) { + Serialize(stream, *p); + } +}; // struct Serialization + +struct Deserialization { + // deserialization + // normal functions + + // ISerializable objects + // T instead of ISerializable is needed to call proper constructor + template + static void Deserialize(IStream &stream, T &object) { + object = T(stream); + } + template + 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 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 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 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 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 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 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 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 ptr(buf); + stream.Read(length, buf); + buf[length] = 0; + str = new std::string(buf); + } + + // STL templates + + // std::list + template + static void Deserialize(IStream &stream, std::list &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 + static void Deserialize(IStream &stream, std::list *&list) { + list = new std::list; + std::unique_ptr> ptr(list); + Deserialize(stream, *list); + ptr.release(); + } + + // std::vector + template + static void Deserialize(IStream &stream, std::vector &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 + static void Deserialize(IStream &stream, std::vector *&vec) { + vec = new std::vector; + std::unique_ptr> ptr(vec); + Deserialize(stream, *vec); + ptr.release(); + } + + // std::set + template + static void Deserialize(IStream &stream, std::set &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 + static void Deserialize(IStream &stream, std::pair &p) { + Deserialize(stream, p.first); + Deserialize(stream, p.second); + } + template + static void Deserialize(IStream &stream, std::pair *&p) { + p = new std::pair; + std::unique_ptr> ptr(p); + Deserialize(stream, *p); + ptr.release(); + } + + // std::tuple + template + static inline typename std::enable_if::type + Deserialize(IStream&, std::tuple&) + {} + + template + static inline typename std::enable_if::type + Deserialize(IStream& stream, std::tuple& t) { + Deserialize(stream, std::get(t)); + Deserialize(stream, t); + } + + template + static void Deserialize(IStream &stream, std::tuple *&t) { + t = new std::tuple; + std::unique_ptr> ptr(t); + Deserialize(stream, *t); + ptr.release(); + } + + // std::map + template + static void Deserialize(IStream &stream, std::map &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 + static void Deserialize(IStream &stream, std::map *&map) { + map = new std::map; + std::unique_ptr> ptr(map); + Deserialize(stream, *map); + ptr.release(); + } + + template + 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 index 0000000..1bdc485 --- /dev/null +++ b/src/util/symbol-visibility.h @@ -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")))