Add ACL helper 19/318719/18
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 22 Jan 2025 15:20:04 +0000 (16:20 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 5 Feb 2025 12:30:21 +0000 (13:30 +0100)
Change-Id: Ie21acf4a60d67242f896d89bbf16d3167e549a44

src/common/CMakeLists.txt
src/common/acl.cpp [new file with mode: 0644]
src/common/include/acl.h [new file with mode: 0644]

index 8508c9c40ce19ed3356891b9356f02447f36f5cd..f1e6c984dad08f8359d90dc23edb39740fc86e84 100644 (file)
@@ -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 (file)
index 0000000..893dabf
--- /dev/null
@@ -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<EntryPtr> _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<EntryPtr> &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<acl_t, decltype(freeAcl)> 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 (file)
index 0000000..efe2c2d
--- /dev/null
@@ -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 <acl/libacl.h>
+#include <vector>
+#include <memory>
+
+#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<Entry>;
+
+    template<typename Id, acl_tag_t Tag>
+    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<uid_t, ACL_USER>;
+    using GidEntry = IdEntry<gid_t, ACL_GROUP>;
+
+    class Exception
+    {
+    public:
+        DECLARE_EXCEPTION_TYPE(SecurityManager::Exception, Base)
+    };
+
+    Acl(Acl&& other);
+    Acl& operator=(Acl&& other);
+
+    Acl() : Acl(std::vector<EntryPtr>())
+    {
+    }
+    ~Acl();
+
+    static Acl Make(acl_perm_t ownerPerms,
+                    acl_perm_t groupPerms,
+                    acl_perm_t otherPerms,
+                    std::vector<EntryPtr> entries = {});
+
+    void apply(const std::string &path, acl_type_t type) const;
+
+private:
+    explicit Acl(const std::vector<EntryPtr> &entries);
+
+    mutable acl_t m_acl = nullptr;
+};
+
+} // namespace SecurityManager