From: Krzysztof Jackiewicz Date: Wed, 22 Jan 2025 15:20:04 +0000 (+0100) Subject: Add ACL helper X-Git-Tag: accepted/tizen/unified/20250217.155039~15 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2377d4889dd8682b48a76b96bb66b0b6b2034dfb;p=platform%2Fcore%2Fsecurity%2Fsecurity-manager.git Add ACL helper Change-Id: Ie21acf4a60d67242f896d89bbf16d3167e549a44 --- diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 8508c9c4..f1e6c984 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -72,6 +72,7 @@ SET(COMMON_SOURCES ${DPL_PATH}/core/src/errno_string.cpp ${DPL_PATH}/db/src/naive_synchronization_object.cpp ${DPL_PATH}/db/src/sql_connection.cpp + ${COMMON_PATH}/acl.cpp ${COMMON_PATH}/channel.cpp ${COMMON_PATH}/check-proper-drop.cpp ${COMMON_PATH}/config-file.cpp diff --git a/src/common/acl.cpp b/src/common/acl.cpp new file mode 100644 index 00000000..893dabfb --- /dev/null +++ b/src/common/acl.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd. All rights reserved + * + * This file is licensed under the terms of MIT License or the Apache License + * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details. + * See the LICENSE file or the notice below for Apache License Version 2.0 + * details. + * + * 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 "acl.h" + +namespace SecurityManager { + +Acl Acl::Make(acl_perm_t ownerPerms, + acl_perm_t groupPerms, + acl_perm_t otherPerms, + std::vector _entries) +{ + auto entries = std::move(_entries); + + // Acl requires exactly one ACL_USER_OBJ, ACL_GROUP_OBJ and ACL_OTHER entry + entries.reserve(entries.size() + 3); + entries.emplace_back(new Acl::Entry(ownerPerms, ACL_USER_OBJ)); + entries.emplace_back(new Acl::Entry(groupPerms, ACL_GROUP_OBJ)); + entries.emplace_back(new Acl::Entry(otherPerms, ACL_OTHER)); + + return Acl(entries); +} + +Acl::Acl(const std::vector &entries) +{ + auto freeAcl = [](acl_t *toFree) {acl_free(*toFree);}; + m_acl = acl_init(entries.size()); + if (m_acl == nullptr) { + LogErrno("acl_init"); + Throw(Exception::Base); + } + std::unique_ptr deleter(&m_acl, freeAcl); + + acl_entry_t entry; + for (const auto &e : entries) { + if (0 != acl_create_entry(&m_acl, &entry)) { + LogErrno("acl_create_entry"); + Throw(Exception::Base); + } + + acl_permset_t permset = nullptr; + if (0 != acl_get_permset(entry, &permset)) { + LogErrno("acl_get_permset"); + Throw(Exception::Base); + } + + if (0 != acl_clear_perms(permset)) { + LogErrno("acl_clear_perms"); + Throw(Exception::Base); + } + + for (auto &p : { ACL_READ, ACL_WRITE, ACL_EXECUTE }) { + if (e->permissions & p) { + if (0 != acl_add_perm(permset, p)) { + LogErrno("acl_add_perm"); + Throw(Exception::Base); + } + } + } + if (0 != acl_set_permset(entry, permset)) { + LogErrno("acl_set_permset"); + Throw(Exception::Base); + } + + if (0 != acl_set_tag_type(entry, e->tag)) { + LogErrno("acl_set_tag_type"); + Throw(Exception::Base); + } + + e->setQualifier(entry); + } + + // Acl requires one ACL_MASK entry if there are ACL_USER or ACL_GROUP entries present. + if (0 != acl_calc_mask(&m_acl)) { + LogErrno("acl_calc_mask"); + Throw(Exception::Base); + } + deleter.release(); +} + +void Acl::apply(const std::string &path, acl_type_t type) const +{ + if (m_acl == nullptr) { + LogError("ACL object is not initialized"); + Throw(Exception::Base); + } + + int last; + int ret = acl_check(m_acl, &last); + if (ret != 0) { + if (ret > 0) + LogError("Check failed for entry " << last << ": " << acl_error(ret)); + else + LogErrno("acl_check"); + Throw(Exception::Base); + } + + if (0 != acl_set_file(path.c_str(), type, m_acl)) { + LogErrno("acl_set_file"); + Throw(Exception::Base); + } +} + +Acl::Acl(Acl&& other) +{ + m_acl = other.m_acl; + other.m_acl = nullptr; +} + +Acl& Acl::operator=(Acl&& other) +{ + if (&other != this) + { + m_acl = other.m_acl; + other.m_acl = nullptr; + } + return *this; +} + +Acl::~Acl() +{ + acl_free(m_acl); +} + +} // namespace SecurityManager diff --git a/src/common/include/acl.h b/src/common/include/acl.h new file mode 100644 index 00000000..efe2c2dd --- /dev/null +++ b/src/common/include/acl.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd. All rights reserved + * + * This file is licensed under the terms of MIT License or the Apache License + * Version 2.0 of your choice. See the LICENSE.MIT file for MIT license details. + * See the LICENSE file or the notice below for Apache License Version 2.0 + * details. + * + * 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. + */ + +#pragma once + +#include +#include +#include + +#include "dpl/exception.h" +#include "dpl/log/log.h" +#include "dpl/errno_string.h" + +namespace SecurityManager { + +class Acl +{ +private: + struct Entry + { + virtual void setQualifier(acl_entry_t&) const + { + } + + Entry(acl_perm_t _permissions, acl_tag_t _tag) : + permissions(_permissions), tag(_tag) + { + } + + acl_perm_t permissions; + acl_tag_t tag; + }; + +public: + static constexpr inline acl_perm_t R = ACL_READ; + static constexpr inline acl_perm_t W = ACL_WRITE; + static constexpr inline acl_perm_t X = ACL_EXECUTE; + static constexpr inline acl_perm_t RW = ACL_READ | ACL_WRITE; + static constexpr inline acl_perm_t RX = ACL_READ | ACL_EXECUTE; + static constexpr inline acl_perm_t RWX = ACL_READ | ACL_WRITE | ACL_EXECUTE; + + using EntryPtr = std::unique_ptr; + + template + class IdEntry: public Entry + { + public: + IdEntry(acl_perm_t permissions, Id id) : + Entry(permissions, Tag), m_qualifier(id) + { + } + + private: + void setQualifier(acl_entry_t &entry) const override + { + if (0 != acl_set_qualifier(entry, &m_qualifier)) { + LogErrno("acl_set_qualifier"); + Throw(Exception::Base); + } + } + + Id m_qualifier; + }; + + using UidEntry = IdEntry; + using GidEntry = IdEntry; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(SecurityManager::Exception, Base) + }; + + Acl(Acl&& other); + Acl& operator=(Acl&& other); + + Acl() : Acl(std::vector()) + { + } + ~Acl(); + + static Acl Make(acl_perm_t ownerPerms, + acl_perm_t groupPerms, + acl_perm_t otherPerms, + std::vector entries = {}); + + void apply(const std::string &path, acl_type_t type) const; + +private: + explicit Acl(const std::vector &entries); + + mutable acl_t m_acl = nullptr; +}; + +} // namespace SecurityManager